如何在bash shell中重定向命令输出?

时间:2014-02-25 19:50:56

标签: linux bash shell

我在编写一个小bash命令时遇到问题。基本上我想回显wrapper命令并将real命令的输出重定向到日志文件。

我的.bashrc中的这样的东西不起作用 - 输出仍然到达控制台。

cmd="some_command >& output.log";
echo $cmd;
$cmd;

但是以下工作 - 输出被定向到日志文件中。

cmd = "some_command";
echo $cmd" >& output.log";
$cmd >& output.log;

第一种方法有什么问题?如何解决?

谢谢!

2 个答案:

答案 0 :(得分:6)

使用eval有效,但出于安全原因这是不好的做法。正确的事情是,当您需要在存储以供重用的代码中执行重定向时,定义一个函数:

cmd() { some_command &> output.log; } # define it
declare -p cmd                        # print it
cmd                                   # run it

如果你需要重定向,那么正确的是一个数组:

cmd=( something 'with spaces' 'in args' ) # define it
printf '%q ' "${cmd[@]}"; echo            # print it
"${cmd[@]}"                               # run it

这更安全,因为数组内容不会通过完整的eval传递。想想你是否cmd="something-with $filename"filename包含$(rm -rf /)。如果您使用eval,则会运行rm命令!


为了提供一个更具体的示例,如果以root身份运行,这将阻塞您的系统:

# !!! I AM DANGEROUS DO NOT RUN ME !!!
evil_filename='/tmp/foo $(rm -rf /)'
cmd="echo $evil_filename"             # define it (BROKEN!)
eval "$cmd"                           # run it    (DANGEROUS!)

另一方面,这是安全的:

evil_filename='/tmp/foo $(rm -rf /)'
cmd=( echo "$evil_filename" )         # define it (OK!)
printf '%q ' "${cmd[@]}"; echo        # print it  (OK!)
"${cmd[@]}"                           # run it    (OK!)

...即使你遗漏了一些引用它仍然是安全的 - 它会工作错误,但仍然不会破坏你的系统:

# I'm broken, but not in a way that damages system security
evil_filename='/tmp/foo $(rm -rf /)'
cmd=( echo $evil_filename )           # define it (BROKEN!)
${cmd[@]}                             # run it    (BROKEN!)

这也是安全的:

evil_filename='/tmp/foo $(rm -rf /)'
cmd() { echo "$1"; }                  # define it (OK!)
cmd "$evil_filename"                  # run it    (OK!)

有关更深入的讨论,请参阅BashFAQ #50(正确存储命令序列以供重用)和BashFAQ #48(关于为什么eval是危险的)。

答案 1 :(得分:1)

  

第一种方法有什么问题?

当您在变量中包含重定向运算符时,shell不会将它们视为特殊变量。相反,这些被认为是有关计划的参数。

一种解决方案是使用eval

cmd="some command >& output.log";
eval $cmd;

顺便说一下,以下是错误的:

cmd = "some command";

变量赋值中=周围不能有空格。