在正确处理文件名时,应该在Bash脚本(没有Perl,Python等等)中使用什么成语来为脚本的参数中的另一个程序构建命令行?
正确地说,我的意思是处理带有空格或奇数字符的文件名,而不会无意中导致其他程序将它们作为单独的参数处理(或者,在的情况下 – 如果不正确的话,如果不正确的文件名字符则有效逃脱 – 做更糟糕的事情).
这是我的意思的一个组成例子,在一个不能正确处理文件名的形式中:让我们假设这个脚本(foo)为一个命令构建一个命令行(bar,假设在路径中) foo的输入参数和移动任何看起来像前面的标志,然后调用bar:
#!/bin/bash
# This is clearly wrong
FILES=
FLAGS=
for ARG in "$@"; do
echo "foo: Handling $ARG"
if [ x${ARG:0:1} = "x-" ]; then
# Looks like a flag, add it to the flags string
FLAGS="$FLAGS $ARG"
else
# Looks like a file, add it to the files string
FILES="$FILES $ARG"
fi
done
# Call bar with the flags and files (we don't care that they'll
# have an extra space or two)
CMD="bar $FLAGS $FILES"
echo "Issuing: $CMD"
$CMD
(请注意,这仅仅是一个示例;还有很多其他时间需要执行此操作以及一堆args然后将它们传递到其他程序.)
在一个简单文件名的天真场景中,效果很好.但是如果我们假设一个包含文件的目录
one
two
three and a half
four < five
当然,命令foo *在其任务中失败了:
foo: Handling four < five
foo: Handling one
foo: Handling three and a half
foo: Handling two
Issuing: bar four < five one three and a half two
如果我们实际允许foo发出该命令,那么结果将不是我们所期望的.
以前我试过通过确保每个文件名周围都有引号的简单方法来解决这个问题,但我(非常)很快就知道这不是正确的方法. ?
那是什么?约束:
>我想尽可能简单地保持这个成语(尤其是我能记住它).
>我正在寻找一个通用的习语,因此我编制了条形程序和上面的人为例子,而不是使用真实的场景,人们可能很容易(并且合理地)沿着尝试使用目标中的功能的路线走下去程序.
>我想坚持使用Bash脚本,我不想调用Perl,Python等.
>我很好依赖(其他)标准* nix实用程序,如xargs,sed或tr,前提是我们不会太迟钝(参见上面的#1). (对Perl,Python等程序员抱歉,他们认为#3和#4相结合以形成任意区别.)
>如果重要,目标程序也可能是Bash脚本,也可能不是.我不指望这很重要……
>我不只是想处理空格,我也想正确处理奇怪的字符.
>如果它不处理带有嵌入的nul字符的文件名(字面意思是字符代码0),我就不会感到困扰.如果有人设法在他们的文件系统中创建一个,我并不担心处理它,他们已经非常努力地搞砸了.
伙计们,提前谢谢.
#!/bin/bash
# This appears to work, using Bash arrays
# Start with blank arrays
FILES=()
FLAGS=()
for ARG in "$@"; do
echo "foo: Handling $ARG"
if [ x${ARG:0:1} = "x-" ]; then
# Looks like a flag, add it to the flags array
FLAGS+=("$ARG")
else
# Looks like a file, add it to the files array
FILES+=("$ARG")
fi
done
# Call bar with the flags and files
echo "Issuing (but properly delimited, not exactly as this appears): bar ${FLAGS[@]} ${FILES[@]}"
bar "${FLAGS[@]}" "${FILES[@]}"
这是正确和合理的吗?或者我依靠上面的环境,以后会咬我.它似乎工作,它为我勾选所有其他框(简单,易记,等).它似乎依赖于一个相对较新的Bash功能(FAQ条目#50提及v3.1,但我不确定这是否是他们使用它的一些语法的一般数组),但我认为它很可能我只会处理拥有它的版本.
(如果以上是正确的,你想取消删除你的答案,Ignacio,我会接受它,但我还没有接受任何其他人,尽管我支持我关于仅链接答案的陈述.)