0

我有一个在内部调用 find 的脚本,并且 id 喜欢做这样的事情:

FIND_CRITERIA="-name \"*.[ch]\" -o -name \"*.cpp\" -o -name \"*.hpp\""
if [ "$1" != "" ]; then
  FIND_CRITERIA=$1
fi

echo "Find command: find / ${FIND_CRITERIA} > /tmp/output.txt"
find / ${FIND_CRITERIA} > /tmp/output.txt

它准确地打印出我想要执行的 find 命令。但是它没有正确执行它。

有谁知道为什么?

非常感谢。

4

2 回答 2

3

简短回答:请参阅BashFAQ #50:我正在尝试将命令放入变量中,但复杂的情况总是失败!.

长答案:当 shell 解析类似的命令时find / ${CRITERIA},它首先解析引号、转义等;然后它${CRITERIA}用它们的值替换变量,但不会返回通过它们来查找引号等——它已经完成了。结果,将引号、转义符等放在变量中并没有任何用处。

在 bash 中做这种事情的最好方法是将参数存储在一个数组中:

#!/bin/bash
CRITERIA=(-name "*.[ch]" -o -name "*.cpp" -o -name "*.hpp")

echo "Find command: find / ${CRITERIA} > /tmp/output.txt"
find / "${CRITERIA[@]}" > /tmp/output.txt

...但这不适用于您将 $1 视为一组可选标准的方式。脚本是否需要任何其他参数?如果没有,我建议将搜索条件作为单独的参数而不是单个参数(即./findscript -name "*.c"代替./findscript "-name \"*.c\""),如下所示:

#!/bin/bash
if [ $# -gt 0 ]; then
    CRITERIA=("$@")
else
    CRITERIA=(-name "*.[ch]" -o -name "*.cpp" -o -name "*.hpp")
fi

echo "Find command: find / ${CRITERIA} > /tmp/output.txt"
find / "${CRITERIA[@]}" > /tmp/output.txt

编辑:根据您关于需要允许脚本其他选项/参数的评论,我看到三个选项:

  1. 用于eval将 getopt 参数解析为数组:

    case "$opt" in
        f) eval "CRITERIA=($OPTARG)" ;;
    

    这具有与 相关的所有常见问题eval,主要与以奇怪(并且可能是危险的)方式失败有关,具体取决于作为 OPTARG 传递的内容。伊克。

  2. 如果脚本不需要采用任何“常规”(非选项)参数,则将条件作为常规参数 ( ./script -a -b -c -d -- -name ".cpp" -o -name ".hpp") 传递。这样做的问题是 IIRCgetopts并不--作为选项和常规参数之间的分隔符,因此您必须至少“手动”进行一些解析。更正:至少在 bash 版本 3.2.48 中,自动getopts处理--

  3. 如果您需要传递的唯一标准是-name,您可以使用多个-f选项来指定名称模式来构建标准,例如./script -a -b -c -d -f "*.cpp" -f "*.hpp"

    CRITERIA=()
    ...
    case "$opt" in
        f) if [[ ${#CRITERIA[@]} -eq 0 ]]; then
                CRITERIA=(-name "$OPTARG")
            else
                CRITERIA+=(-o -name "$OPTARG")
            fi ;;
    ...
    
    if [[ ${#CRITERIA[@]} -eq 0 ]]; then
        CRITERIA=(-name "*.[ch]" -o -name "*.cpp" -o -name "*.hpp")
    fi
    
于 2013-04-25T15:52:22.773 回答
1

您正在调用$CRITERIA,而变量名称是$FIND_CRITERIA. 我认为这是一个错字。

试试这个:

 #!/bin/bash

 FIND_CRITERIA="-name \"*.\[ch\]\" -o -name \"*.cpp\" -o -name \"*.hpp\""
 if [ "$1" != "" ]; then
   FIND_CRITERIA=$1
 fi

 echo "Find command: find / ${FIND_CRITERIA} > /tmp/output.txt"
 echo "${FIND_CRITERIA}" | xargs find / > /tmp/output.txt
于 2013-04-25T15:54:13.263 回答