【问题标题】:Got exit code 123 in find + xargs grep在 find + xargs grep 中得到退出代码 123
【发布时间】:2014-12-19 20:55:54
【问题描述】:

这是我的脚本

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 $PATTERN2")

使用 -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")

【问题讨论】:

  • 你为什么在这里使用eval

标签: bash find xargs


【解决方案1】:

123 表示“任何以非零状态退出的调用”。所以xargs 至少运行了两次grep(因为你给它提供了太多的文件,以至于它们会超过最大命令行长度,你限制为 100 个文件)并且至少有一个调用是在一组文件上不包含任何匹配项,这导致来自grep 的退出代码为非零(失败)。

也许您应该解释一下您要完成的工作。 eval 看起来是多余的,双重重定向可能无法完成您想要的(grep 的标准输入不能同时连接到来自eval.P 的管道)。

如果您想将第一个参数参数化为grep,可以执行类似的操作

#!/bin/sh
find -type f -name '*.h' -print0 |
xargs -0 -n100 grep "$1"

... 你在哪里调用它,例如stdio 作为第一个参数。

(请注意find 的参数已大大简化。您只有两个谓词,因此无需括号任何内容,然后-a 也可以删除。)

如果有返回零匹配的 grep 调用,退出代码仍将是 123。您可以通过省略-n 100 来减少机会(无论如何这似乎几乎没有任何有用的目的),但如果您想绝对阻止它,您可以将整个管道提供给| grep .,如果有任何输出,它将报告成功. (或者您可以在包装器上运行xargs,如果grep 的退出代码为0 或1,则该包装器始终返回成功,但这更复杂,即使在零匹配的情况下,您也会看到“成功” .)

【讨论】:

    【解决方案2】:

    我将此作为单独的答案发布,以回应您最近的编辑。我不想改变我现有的答案,它已经解决了基本问题。

    不幸的是,您的脚本是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 是否在任何地方都受支持,但它适用于 GNU grep 并简化了我的想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 1970-01-01
      • 2016-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      相关资源
      最近更新 更多