【发布时间】:2016-07-12 19:36:17
【问题描述】:
我有一系列目录,我需要在这些目录上运行各种 shell 命令,并且我制作了一个名为 dodirs.sh 的简短脚本来简化在每个目录中运行命令:
#!/bin/bash
echo "Running in each directory: $@"
for d in ./*/; do
(
cd "$d"
pwd
eval "$@"
)
done
这对于很多简单的命令来说是可以的,但是有些就麻烦了,比如:
grep "free energy TOTEN" OUTCAR | tail -1
在位于每个目录的文件中查找字符串。
似乎管道和/或引号是麻烦,因为如果我说:
dodirs.sh grep "free energy TOTEN" OUTCAR
我得到了一个明智的(如果 waaaay 到长输出):
Running in each directory: grep free energy TOTEN OUTCAR
...
OUTCAR: free energy TOTEN = -888.53122906 eV
OUTCAR: free energy TOTEN = -888.53132396 eV
OUTCAR: free energy TOTEN = -888.531324 eV
...
我注意到 echo 的结果丢失了引号,所以这有点奇怪。另一方面,如果我说:
dodirs.sh grep "free energy TOTEN" OUTCAR | tail -1
然后我得到了无意义的:
...
grep: energy: No such file or directory
grep: TOTEN: No such file or directory
...
请注意,回声现在根本没有回声,显然是误解了这条线。
有什么方法可以转义字符,或者将参数打包到我的 dodirs.sh 脚本中吗?
也许有人完全知道更好的方法?
【问题讨论】:
-
eval "$@"有点……违反直觉。一般来说,您应该采用文字 argv 数组,在这种情况下您只需使用"$@"来执行它,或者采用单个字符串,在这种情况下您应该使用eval "$string"。 -
...
eval "$string"方法相对于eval "$@"的最大优势在于调用者必须知道它正在使用中才能成功使用它——他们可以'不要认为他们正在调用采用execv方法的东西,而是调用使用eval方法的东西,这是安全漏洞的常见来源。 (例如,你知道ssh使用eval方法吗?很多人不知道,但如果你不知道,你可能没有采取预防措施在命令行上传递不受信任的字符串SSH 安全!) -
...btw,
.sh扩展并不普遍被认为是脚本的良好形式(与库相反,库的扩展应该反映所需的特定解释器 - 因此,.bash用于bash,.ksh用于 ksh,.sh用于 POSIX sh 等)。请参阅wooledge.org/~greybot/meta/.sh,了解来自 irc.freenode.org #bash 频道关于该主题的 factoid 的历史(反映社区共识)。