在 Bash 脚本中,我传递带有参数的命令。除非命令包含重定向,否则这工作正常。在这种情况下,重定向字符被视为普通字符。
$ cat foo
#!/bin/bash
f() {
echo "command: $@"
$@
}
f echo a-one a-two
f 'echo b-one b-two'
f 'echo c-one c-two > c.tmp'
# I don't want to do f echo d-one d-two > d.tmp because I want to redirect the
# output of the passed command, not the output of the f() function.
$ ./foo
command: echo a-one a-two
a-one a-two
command: echo b-one b-two
b-one b-two
command: echo c-one c-two > c.tmp
c-one c-two > c.tmp
如您所见,当我想将“c-one c-two”打印到文件 c.tmp 时,这将打印“c-one c-two > c.tmp”。有没有办法做到这一点?
答案1
f() {
echo "command: $@"
$@
}
但你是对的,运行这样的命令不会处理 shell 操作符,无论是重定向还是&&
.您可以将该函数更改为其eval
获取的命令,这将处理重定向,但也可以处理其他所有内容。
特别是,传递任意文件名将再次变得困难。例如,这最终将ls
在两个文件上运行foo
:bar
run_with_eval() {
eval "$@"
}
file='foo bar'
run_with_eval ls -l "$file"
你必须安排文件名被引用对于 shell 来说,这有点尴尬并且容易出错。
但如果你仅有的想要重定向,甚至更好,只输出重定向>
,你可以让函数手动处理它:
#!/bin/bash
run_with_redir() {
local redir=
if [[ $1 = '>' ]]; then
redir=$2
shift 2
fi
## whatever else you do
if [[ $redir ]]; then
"$@" > "$redir"
else
"$@"
fi
}
run_with_redir echo "normal command, no redirection"
run_with_redir ">" output.txt echo "this gets redirected to output.txt"
也就是说,使用>
文件名作为前两个参数调用函数,将其余参数作为命令运行,并重定向输出。如果没有>
,它会正常运行命令。请注意,">"
调用函数时必须加引号,否则我们将再次获得整个函数的输出重定向。将其扩展为支持eg>>
应该很简单,即使是重复的。
这也应该适用于更棘手的情况:
run_with_redir ">" "output file with space.txt" ls -l "other file with space"
答案2
答案3
一种不使用 eval 的方法,但它也非常不安全。
#!/bin/bash
f() {
echo "command: $@"
bash -c "$@"
}
f echo a-one a-two
f 'echo b-one b-two'
f 'echo c-one c-two > c.tmp'