为什么bash不能接受命令选项作为字符串?

时间:2016-09-25 02:55:48

标签: bash

我尝试了以下代码。

command1="echo"
"${command1}" 'case1'

command2="echo -e"
"${command2}" 'case2'

echo -e 'case3'

输出如下,

case1
echo -e: command not found
case3

case2导致错误但类似情况,case1和case3运行良好。看来带有选项的命令无法被识别为有效命令。

我想知道为什么它不起作用。请教我。非常感谢你。

3 个答案:

答案 0 :(得分:5)

案例1(未修改)

command1="echo"
"${command1}" 'case1'

作为一种成语,这是一种不好的做法,但没有任何不正确的做法。

案例2(未修改)

command2="echo -e"
"${command2}" 'case2'

这是一个名为/usr/bin/echo -e的程序,其中空格是其名称的一部分

案例2(减少行情)

# works in this very specific case, but bad practice
command2="echo -e"
$command2 'case2' # WITHOUT THE QUOTES

...这个有效,但只是因为你的命令不够有趣(没有引号,没有反斜杠,没有其他shell语法)。请参阅BashFAQ #50,了解一般情况下这不是一种可接受的做法的原因。

案例X(eval - 不良做法,Oft建议)

您经常会看到这一点:

eval "$command1 'case1'"

...在这个非常特殊的情况下,command1和所有参数都是硬编码的,这并不是特别有害。但是,只有很小的改变,它极其有害:

# SECURITY BUGS HERE
eval "$command1 ${thing_to_echo}"

...如果thing_to_echo='$(rm -rf $HOME)',你将度过非常糟糕的一天。

最佳实践

通常,命令不应存储在字符串中。使用功能:

e() { echo -e "$@"; }
e "this works"

...或者,如果你需要逐步建立你的参数列表,一个数组:

e=( echo -e )
"${e[@]}" "this works"

旁边:在echo -e

echo的任何实现-e除了在输出is failing to comply with the relevant POSIX standard上发出字符-e之外的其他任何内容,建议使用printf代替({1}}使用部分)。

改为考虑:

# a POSIX-compliant alternative to bash's default echo -e
e() { printf '%b\n' "$*"; }

...这不仅可以提供与非bash shell的兼容性,而且如果使用--enable-xpg-echo-default--enable-usg-echo-default进行编译,或者shopt -s xpg_echoBASHOPTS=xpg_echo,则修复了对POSIX模式下bash的支持设置,或者在启动时shell的环境中是否存在{{1}}。

答案 1 :(得分:2)

如果变量command包含值echo -e 给shell的命令行是:

"$command" 'case2'

shell将搜索名为echo -e的命令,其中包含空格 该命令不存在,shell报告错误。

the image linked below, from O'Reilly's Learning the Bash Shell, 3rd Edition中描述了发生这种情况的原因:

Learning the bash Shell, 3rd Edition
By Cameron Newham
...............................................
Publisher: O'Reilly
Pub Date: March 2005
ISBN: 0-596-00965-8
Pages: 352

如果引用变量(按照右箭头),它几乎(直接通过步骤6,7和8)直接执行到步骤12中执行。
因此,搜索的命令没有在空格上分割。

原始图片(由于@CharlesDuffy投诉删除,我不同意,但是好的,让我们转向不可能出错的一方)就在这里:

Link to original image in the web site where I found it.

如果给shell的命令行没有引用:

$command 'case2'

字符串command在步骤6(参数展开)中展开,然后变量$commandecho -e的值在步骤9中划分:“单词拆分”。 然后shell搜索带有参数echo的命令-e。 命令echo“看到”-e的参数并将echo作为一个选项进行处理。

尝试将命令存储在字符串中是一个非常糟糕的主意 试试这个,仔细想想你会期待什么,然后对执行感到惊讶:

$ command='echo -e case2; echo "next line"'; $command

要查看会发生什么,请执行以下命令:

$ set -vx; $command; set +vx

答案 2 :(得分:-2)

如果我以这种方式发出命令,它可以在我的机器上运行:

cmd2="echo -e"

如果您仍然遇到问题,我建议将选项存储在另一个变量中,这样如果您正在进行shell脚本编写,那么使用类似选项值的多个命令可以利用该变量,所以也尝试这样的事情。

cmd1="echo"
opt1="-e"
$cmd1 $opt1 Hello