我有一个 bash 脚本,它在一次执行之前根据一些参数在字符串中构建一个命令行。连接到命令字符串的部分应该由管道分隔,以促进通过每个组件的数据“流”。
一个非常简单的例子:
#!/bin/bash
part1=gzip -c
part2=some_other_command
cmd="cat infile"
if [ ! "$part1" = "" ]
then
cmd+=" | $part1"
fi
if [ ! "$part2" = "" ]
then
cmd+=" | $part2"
fi
cmd+="> outfile"
#show command. It looks ok
echo $cmd
#run the command. fails with pipes
$cmd
Run Code Online (Sandbox Code Playgroud)
出于某种原因,管道似乎不起作用。当我运行这个脚本时,我收到不同的错误消息,通常与命令的第一部分(在第一个管道之前)有关。
所以我的问题是是否可以以这种方式构建命令,最好的方法是什么?
wal*_*tor 17
这一切都取决于对事物进行评估的时间。当您键入时$cmd,该行的其余部分将作为参数传递给 in 中的第一个单词$cmd。
walt@spong:~(0)$ a="cat /etc/passwd"
walt@spong:~(0)$ b="| wc -l"
walt@spong:~(0)$ c="$a $b"
walt@spong:~(0)$ echo $c
cat /etc/passwd | wc -l
walt@spong:~(0)$ $c
cat: invalid option -- 'l'
Try 'cat --help' for more information.
walt@spong:~(1)$ eval $c
62
walt@spong:~(0)$ a="echo /etc/passwd"
walt@spong:~(0)$ c="$a $b"
walt@spong:~(0)$ echo $c
echo /etc/passwd | wc -l
walt@spong:~(0)$ $c
/etc/passwd | wc -l
walt@spong:~(0)$ $c |od -bc
0000000 057 145 164 143 057 160 141 163 163 167 144 040 174 040 167 143
/ e t c / p a s s w d | w c
0000020 040 055 154 012
- l \n
0000024
walt@spong:~(0)$ eval $c
1
Run Code Online (Sandbox Code Playgroud)
这表明传递给echo命令的参数是:“ /etc/passwd”、“ |”(竖线字符)、“ wc”和“ -l”。
来自man bash:
eval [arg ...]
The args are read and concatenated together into
a single command. This command is then read and
executed by the shell, and its exit status is returned
as the value of eval. If there are no args, or only null
arguments, eval returns 0.
Run Code Online (Sandbox Code Playgroud)
为了将来参考,对此的一种解决方案是使用“eval”。这确保了 bash 解释字符串的任何方式都被遗忘,并且整个内容都被读取,就好像它是直接在 shell 中键入的一样(这正是我们想要的)。
所以在上面的例子中,替换
$cmd
Run Code Online (Sandbox Code Playgroud)
和
eval $cmd
Run Code Online (Sandbox Code Playgroud)
解决了。
| 归档时间: |
|
| 查看次数: |
48590 次 |
| 最近记录: |