文件名周围的引号会使 bash 脚本混乱

文件名周围的引号会使 bash 脚本混乱

我正在编写一个脚本,将命令应用于大量文件。我自动化执行此操作的方式归结为

#!/bin bash
for in_file in ${PWD}/*/*/*.txt; do
    out_file="${in_file//in/out}"
    CM="/usr/local/bin/command -in \"${in_file}\" -out \"${out_file}\""
    echo ${CM}
    ${CM}
done

我得到的典型输出是

/usr/local/bin/command -in "/home/user/infile.txt" -out "/home/user/outfile.txt"
error:
/usr/local/bin/command: unable to find file "/home/user/infile.txt"
...

但是然后我在命令提示符上逐字逐句地剪切并粘贴相同的命令,包括所有的引号等,它运行起来没有问题!

因为许多文件名(不是我做的!)都有空格,所以我需要在脚本中使用引号。但有人能告诉我为什么它们在脚本中不起作用而在命令提示符下起作用吗?有没有办法正确地做到这一点?

答案1

使用数组:这是保存带有空格的参数的多字命令的最佳方法。

#!/bin bash
for in_file in ${PWD}/*/*/*.txt; do
    out_file="${in_file//in/out}"
    cmd=( /usr/local/bin/command -in "$in_file" -out "$out_file" )
    echo "${cmd[@]}"
    "${cmd[@]}"
done

答案2

“${CM}”不会使用空白字符作为分隔符。因此 bash 认为整个字符串是程序的名称。

使用 ${CM} bash 认为“是参数的一部分。

您可以使用 << eval "${CM}" >>,但文件名中未转义的特殊字符可能会产生副作用。

因此更好的做法如下:

这有用吗?

#!/bin bash
for in_file in "$PWD"/*/*/*.txt; do
    out_file="$in_file/in/out"
    CM="/usr/local/bin/command -in \"$in_file\" -out \"$out_file\""
    echo "${CM}"
    /usr/local/bin/command -in "$in_file" -out "$out_file"
done

不要回显命令,而是使用“set -x”来调试脚本:

#!/bin bash
set -x
for in_file in "$PWD"/*/*/*.txt; do
    out_file="$in_file/in/out" 
    /usr/local/bin/command -in "$in_file" -out "$out_file"
done

或这个 :

#!/bin bash
for in_file in "$PWD"/*/*/*.txt; do
    out_file="$in_file/in/out" 
    set -x
    /usr/local/bin/command -in "$in_file" -out "$out_file"
    set +x
done

相关内容