这是我的剧本
eval "find \\( -type f -a \\( -name '*.h' \\) \\) -print0" | xargs -0 -n100 grep -f <(echo "stdio")
echo $?
找不到任何内容,退出代码为123。
如果我稍微修改一下
echo "stdio" >.P
eval "find \\( -type f -a \\( -name '*.h' \\) \\) -print0" | xargs -0 -n100 grep <.P
echo $?
找到了一些东西,但退出代码仍然是123。
那有什么不对?
=============================================== =======================
实际上我只想编写一个小脚本来使find + xargs + grep更容易。例如,
xgrep -e PATTERN1 -e PATTERN2 ... * .c * .h
是执行
find -name * .c -o -name * .h | xargs grep -f&lt;(echo&#34; $ PATTEN1
$ PATTERN2&#34)
使用-f选项而不是-e是为了避免在模式中转义单个或双重的方法时遇到麻烦。
#!/bin/bash
#set -e -o pipefail
eval ARGV=($(getopt -l '' -o 'e:li' -- "$@")) || exit 1
for((i=0;i<${#ARGV[@]};i++)) {
o="${ARGV[$i]}"
case $o in
-e)
i=$((i+1));
a="${ARGV[$i]}"
if [ -n "$grep_patterns" ]; then
grep_patterns="$grep_patterns"$'\n'
fi
grep_patterns="$grep_patterns$a"
;;
-i)
grep_options="$grep_options -i"
;;
-l)
grep_options="$grep_options -l"
;;
--)
i=$((i+1));
break;;
esac
}
for((;i<${#ARGV[@]};i++)) {
if [ -n "$find_options" ]; then
find_options="$find_options -o "
fi
find_options="${find_options}-name '${ARGV[$i]}'"
}
cmd="find \\( -type f -a \\( $find_options \\) \\) -print0"
eval "$cmd" | xargs -0 grep $grep_options -f <(echo "$grep_patterns")
答案 0 :(得分:4)
123表示&#34;任何以非零状态退出的调用&#34;。所以xargs
运行grep
至少两次(因为你提供了太多的文件,它们将超过最大命令行长度,你限制为100个文件)并且至少有一个调用是在一个包含不匹配的文件集,导致grep
的退出代码非零(失败)。
也许你应该解释一下你想要完成的事情。 eval
看起来多余,双重定向可能无法完成您想要的任务(grep
的标准输入无法同时连接到eval
和{{1}的管道}})。
如果要将第一个参数参数化为.P
,可能会执行类似
grep
...你用例如调用它的地方#!/bin/sh
find -type f -name '*.h' -print0 |
xargs -0 -n100 grep "$1"
作为第一个参数。
(另请注意stdio
的简化参数。您只有两个谓词,因此不需要对任何内容进行括号,然后也可以删除find
。)
如果有-a
次调用返回零匹配,则退出代码仍为123。您可以通过省略grep
(这似乎无论如何似乎没有任何有用的用途)来减少机会,但如果您想要绝对阻止它,您可以将整个管道提供给-n 100
,如果您要报告成功,有任何输出。 (或者您可以在包装器上运行| grep .
,如果xargs
的退出代码为0或1,则总是返回成功,但这会更复杂,然后您将看到&#34;成功&# 34;即使在零匹配的情况下也是如此。)
答案 1 :(得分:1)
我将此作为单独的答案发布,以回应您最近的编辑。我并不特别想改变现有的答案,这已经解决了基本问题。
遗憾的是,您的脚本是http://mywiki.wooledge.org/BashFAQ/050中描述的问题的典型示例:“我正在尝试将命令放在变量中,但是......”
简短版本是“不要那样做”。长版本是,尝试使用数组,并避免变量不是绝对必要的。这是尝试按照这些方式重构您的工具。
#!/bin/bash
#set -e -o pipefail
grep_patterns=( )
grep_options=( )
eval ARGV=($(getopt -l '' -o 'e:li' -- "$@")) || exit 1
for((i=0;i<${#ARGV[@]};i++)) {
case ${ARGV[$i]} in
-e) i=$((i+1))
grep_patterns+=("-e" "${ARGV[$i]}") ;;
-i | -l)
grep_options+=("${ARGV[$i]}") ;;
--) i=$((i+1));
break;;
esac
}
find_options=("${ARGV[@]:$i}")
find -type f -a \( "${find_options[@]}" \) -print0 |
xargs -0 grep "${grep_options[@]}" "${grep_patterns[@]}"
我不确定将-e
多个grep
选项传递给grep
,但它适用于GNU {{1}},并简化了我的想法。