【问题标题】:Why is xargs' exit code different based on the presence of "-I" option?为什么 xargs 的退出代码会因“-I”选项的存在而不同?
【发布时间】:2019-04-10 17:25:04
【问题描述】:

阅读 xargs man page 后,我无法理解以下 xargs 调用的退出代码的区别。

(当我遇到这种行为时,最初的目的是结合 find 和 grep 来检查所有给定文件中是否存在表达式)

复制:

(如果使用 zsh 强制创建文件,则使用 >>!

# Create the input files.
echo "a" >> 1.txt   
echo "ab" >> 2.txt

# The end goal is to check for a pattern (in this case simply 'b') inside
# ALL the files returned by a find search. 
find .  -name "1.txt" -o -name "2.txt" | xargs -I {}  grep -q "b"  {}
echo $?
  123  # Works as expected since 'b' is not present in 1.txt

find .  -name "1.txt" -o -name "2.txt" | xargs grep -q "b"
echo $?
  0   # Am more puzzled by why the behaviour is inconsistent

手册页上的 EXIT_STATUS 部分说:

xargs exits with the following status:
0 if it succeeds
123 if any invocation of the command exited with status 1-125
124 if the command exited with status 255
125 if the command is killed by a signal
126 if the command cannot be run
127 if the command is not found
1 if some other error occurred.

我会认为,无论是否使用-I123 if any invocation of the command exited with status 1-125 都应该适用?

您能否分享任何见解来解释这个难题?

【问题讨论】:

标签: grep find posix xargs exit-code


【解决方案1】:

下面是 -I 选项与 xargs 的效果的证据,它借助显示调用次数的包装脚本:

cat ./grep.sh
#/bin/bash

echo "I am being invoked at $(date +%Y%m%d_%H-%M-%S)"
grep $@

(实际调用的命令,在这种情况下grep 并不重要)

现在使用包装脚本执行与问题中相同的命令:

❯ find .  -name "1.txt" -o -name "2.txt" | xargs -I {}  ./grep.sh -q "b" {}
I am being invoked at 20190410_09-46-29
I am being invoked at 20190410_09-46-30

❯ find .  -name "1.txt" -o -name "2.txt" | xargs ./grep.sh -q "b"
I am being invoked at 20190410_09-46-53

我刚刚发现了一个对回答这个问题的类似问题的答案的评论(完全归功于 https://superuser.com/users/49184/daniel-andersson 他的智慧):

https://superuser.com/questions/557203/xargs-i-behaviour#comment678705_557230

此外,未加引号的空格不会终止输入项;相反,分隔符是换行符。 ——这是理解行为的核心。如果没有 -I,xargs 只会将输入视为单个字段,因为换行符不是字段分隔符。使用 -I,突然换行符成为字段分隔符,因此 xargs 看到三个字段(它迭代)。这是一个非常微妙的观点,但在引用的手册页中进行了解释。

-I replace-str
   Replace occurrences of replace-str in the initial-arguments
   with names read from standard input.  Also, unquoted blanks do
   not terminate input items; instead the separator is the
   newline character.  Implies -x and -L 1.

基于此,

find .  -name "1.txt" -o -name "2.txt"  
#returns
# ./1.txt 
# ./2.txt

xargs -I {}  grep -q "b"  {}
# interprets the above as two separate lines since,
# with -I option the newline is now a *field separator*. 
# So this results in TWO invocations of grep and since one of them fails, 
# the overall output is 123 as documented in the EXIT_STATUS section

xargs grep -q "b"
# interprets the above as a single input field,
# so a single grep invocation which returns a successful exit code of 0 since the pattern was found in one of the files.

【讨论】:

    猜你喜欢
    • 2016-12-22
    • 2019-10-12
    • 2020-11-17
    • 2011-01-11
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    相关资源
    最近更新 更多