grep - 为什么 xargs 的退出代码会因“-I”选项的存在而不同?
问题描述
阅读 xargs手册页后,我无法理解以下 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.
我原以为,123 if any invocation of the command exited with status 1-125
无论是否-I
使用,这都应该适用?
您能否分享任何见解来解释这个难题?
解决方案
-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.
推荐阅读
- angularjs - Angular,Chrome - 所有请求都停止了大约 450 毫秒
- python - 如何让 Python 应用程序与终端通信
- javascript - js函数中的css动画调用不起作用
- javascript - 如何在引导模式将其添加到主体以调整窗口滚动时获取填充右变量的值?
- php - 发送 smtp 邮件 laravel 不工作
- java - 登录 Facebook 后 Android webView 不回来?
- amazon-web-services - 捕获 S3 文件下载开始和结束时间以及其他详细信息
- azure - 如何通过 Azure DevOps 从 Azure 中删除存储帐户
- xamarin - 带有 Xamarin 应用程序的 VS2017 和 Win7 中的命名空间问题?
- java - Maven 无法使用 OpenJDK 11 找到 jaxb-api,即使它存在于存储库中