如果stdin输入为空,如何忽略xargs命令?

Hyd*_*erA 168 bash centos xargs

考虑这个命令:

ls /mydir/*.txt | xargs chown root
Run Code Online (Sandbox Code Playgroud)

目的是将所有文本文件的所有者更改mydir为root

问题是,如果没有.txt文件,mydir则xargs会发出一条错误,指出没有指定路径.这是一个无害的例子,因为被抛出一个错误,但在某些情况下,如在我需要在这里使用的脚本,假设一个空白的路径是当前目录.因此,如果我/home/tom/从那时起运行该命令,如果没有结果,ls /mydir/*.txt并且所有文件/home/tom/都将其所有者更改为root.

那么我如何让xargs忽略空结果呢?

Sve*_*ach 270

对于GNU xargs,您可以使用-r--no-run-if-empty选项:

--no-run-if-empty
-r
如果标准输入不包含任何非空白,请不要运行该命令.通常,即使没有输入,命令也会运行一次.此选项是GNU扩展.

  • 不幸的是,这不适用于Mac.既不是短期也不是长期期权. (26认同)
  • 老实说,我先在谷歌搜索并找到了这个(但不会在没有阅读手册的情况下提出要求).我有点认为这应该是默认行为,不需要开关来启用它. (9认同)
  • @wedi - OSX有BSD用户空间,所以这种事情会经常发生.您可以使用自制程序来安装GNU fileutils来解决它. (7认同)
  • 你的意思是'brew install findutils`.`findutils`,而不是`fileutils`. (7认同)
  • 在macOS上,不提供标志会导致始终无法运行命令,因此我猜想它是不需要的。 (2认同)

ari*_*lCo 14

非GNU的xargs用户可以利用的-L <#lines>,-n <#args>,-i,和-I <string>:

ls /empty_dir/ | xargs -n10 chown root # chown executed every 10 args or fewer
ls /empty_dir/ | xargs -L10 chown root # chown executed every 10 lines or fewer
ls /empty_dir/ | xargs -i cp {} {}.bak # every {} is replaced with the args from one input line
ls /empty_dir/ | xargs -I ARG cp ARG ARG.bak # like -i, with a user-specified placeholder
Run Code Online (Sandbox Code Playgroud)

请记住,xargs在空白处拆分行,但引用和转义是可用的; RTFM了解详情.

  • 是! 在MAC OSX上,`echo''| xargs -n1 echo blah`什么都不做; 而`echo'x'| xargs -n1 echo blah`打印"blah". (4认同)
  • 需要注意的是`echo'' | xargs -n1 echo blah` 使用 GNU 的 `xargs` 打印 `blah`。 (4认同)
  • 似乎没有回答这个问题? (2认同)
  • @Nicolas:如果您的`xargs`版本不支持`--no-run-if-empty`开关并尝试在没有STDIN输入的情况下运行命令参数,那么这是防止执行的方法(在Solaris 10中就是这种情况) ).其他unix中的版本可能只是忽略空列表(例如AIX). (2认同)
  • 对于GNU和BSD/OSX支持,我最终使用的东西:`ls /mydir/*.txt | xargs -n 1 -I {} chown root {}`,正如这个答案所暗示的那样. (2认同)

thi*_*ton 11

man xargs--no-run-if-empty.

  • 如果您使用的是 OSX,则不会。如果你好奇为什么,edk750 在他们的评论中解释了这一点。 (2认同)

ken*_*orb 9

xargs你而言,你可以-r按照建议使用,但BSD不支持它xargs.

因此,作为解决方法,您可以传递一些额外的临时文件,例如:

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root $(mktemp)
Run Code Online (Sandbox Code Playgroud)

或者将其stderr重定向到null(2> /dev/null),例如

find /mydir -type f -name "*.txt" -print0 | xargs -0 chown root 2> /dev/null || true
Run Code Online (Sandbox Code Playgroud)

另一种更好的方法是使用while循环迭代找到的文件:

find /mydir -type f -name "*.txt" -print0 | while IFS= read -r -d '' file; do
  chown -v root "$file"
done
Run Code Online (Sandbox Code Playgroud)

另请参阅:在Mac OS X中忽略xargs的空结果


另请注意,您更改权限的方法并不好,不鼓励使用.当然你不应该解析ls命令的输出(参见:为什么你不应该解析ls的输出).特别是当您通过root运行命令时,因为您的文件可以包含可由shell解释的特殊字符,或者想象具有空格字符的文件/,那么结果可能很糟糕.

因此,您应该改变您的方法并使用find命令,例如

find /mydir -type f -name "*.txt" -execdir chown root {} ';'
Run Code Online (Sandbox Code Playgroud)


alf*_*era 9

-r使用/ --no-run-if-emptyxargs 参数的跨平台(Mac 和 Linux)替代方案:

具有空参数的示例(Ubuntu 18.04 和 Big Sur 上的结果相同):

$ echo | xargs -I {}  echo "This is a test with '{}'"
$
$
$ cat /dev/null | xargs -I {}  echo "This is a test with '{}'"
$
Run Code Online (Sandbox Code Playgroud)

多行示例:

$ seq 1 5  | xargs -I {}  echo "This is a test with '{}'"
This is a test with '1'
This is a test with '2'
This is a test with '3'
This is a test with '4'
This is a test with '5'
$
Run Code Online (Sandbox Code Playgroud)