为什么推荐使用“printf--”而不是“回声?“

为什么推荐使用“printf--”而不是“回声?“

在里面重击陷阱在“Greg's Wiki”上我发现了以下引用:

事实上,echo这里使用该命令并不能绝对安全。-n例如,如果变量包含,echo将认为是一个选项,而不是要打印的数据。打印变量值的唯一绝对可靠的方法是使用printf

printf "%s\n" "$foo"

但是当我输入:

var="-n Hello"
echo "$var"

它工作正常并且不会解释-n为一个选项,所以我不明白为什么我引用的消息来源说我们需要使用它printf才能绝对安全?

答案1

在您的示例中,它“偶然”正常工作。原因是这样的

  • 您仅向 提供了一个参数echo,并且
  • 您已按建议引用了变量。

这意味着echo只将一个字符串视为命令行参数,即-n Hello,包括“单词”之间的空格。现在,echo(好吧,有些echos)被编程为它识别-n为一个选项,但不是 string -n<space>Hello,所以它会假设这是一个操作数- 即您想要“按原样”打印的字符串(好吧,可能会\扩展序列)。

如果你用过

echo $var

如果没有引号,并且默认值为$IFS$var则将在空格处拆分,并且echo会看到论点:-n-它将解释为一个选项- 和Hello

这意味着在这种情况下,正确引用 shell 变量是防止无意中遇到echo将操作数解释为选项的情况的补救措施。

然而:

  1. 请记住,链接源中的示例是通过“全局扩展”( ) 打印文件列表*.zip,其中变量必须不加引号使用,因此并不总是可以使用该保护。

  2. 引用变量仅在以下情况下才有帮助:分词会导致echo看到一个选项参数。如果要打印的参数一-n开始就是单个参数,则引用无法帮助您。

    例如,考虑这样一种情况,您收集了要打印的字符串数组echo,并且其中一个字符串恰好也是以下的选项参数echo

    arguments=( "-n" "Hello" )
    

    然后,即使您正确引用该变量,如

    echo "${arguments[@]}"
    

    第一个标记echo看到的仍然是-n它解释为选项,而不是操作数。如果您只是将多个变量作为参数传递给echo,并且第一个变量是 或 开头,情况也是如此-n。在这里,引用变量也无济于事。

  3. 在一般情况下,如果程序接受以下形式的参数,即使引用也无济于事-oValue

    作为假设的情况,采用一个my_formula_renderer排版数学公式并接受选项参数 的程序。然后,假设您想要排版公式,如-sfontsize-sqrt(a^2 + b^2)

    ./my_formula_renderer "-sqrt(a^2+b^2)"
    

    如果您的程序没有--结束选项解析的说明符,它会认为您尝试使用 的字体大小排版“无” qrt(a^2+b^2),而不是使用默认字体大小的上述公式。

    如果-s和其他公式元素之间有明确的空格,例如"-s +2t +u^2"; ,它甚至没有帮助。它可能只是将其误解为+2t +u^2带有前导空格的“字体大小”(请参阅例如这个问题这成为了一个问题)。

  4. 如果程序接受单字母选项的“聚类”,情况也是如此。

    正如 @Stéphane Chazelas 所指出的,echo例如,可以将字符串解释-neEenennne为选项-n-e和的串联-E,因此尝试通过打印该字符串echo可能会失败/以意想不到的方式表现。

  5. 除了选项处理之外,echo(某些echos,包括启用选项bash时的 s,xpg_echo在某些版本中默认情况下)会将\n\\等扩展\b为换行符、反斜杠、退格字符,因此不能用于输出可能包含反斜杠的逐字字符串

TL/DR

关键点是您引用的来源中的“绝对”一词,以及它echo具体指代的事实。大多数情况下,echo都会好的。但如果你开始盲目地依赖它,就会出现这样的情况(迟早)echo,或者实际上是你调用的另一个更关键的程序,无意中将您打算作为“操作数”参数的内容误解为“选项”参数,通常当您将其作为 shell 变量传递时。

相关内容