我在编写一个小bash命令时遇到问题。基本上我想回显wrapper命令并将real命令的输出重定向到日志文件。
我的.bashrc中的这样的东西不起作用 - 输出仍然到达控制台。
cmd="some_command >& output.log";
echo $cmd;
$cmd;
但是以下工作 - 输出被定向到日志文件中。
cmd = "some_command";
echo $cmd" >& output.log";
$cmd >& output.log;
第一种方法有什么问题?如何解决?
谢谢!
答案 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";
变量赋值中=
周围不能有空格。