如果您已经关注 unix.stackexchange.com 一段时间了,那么您现在应该知道,echo $var在 Bourne/POSIX shell(zsh 是例外)中的列表上下文(如)中不加引号的变量具有非常特殊的含义,并且除非你有很好的理由,否则不应该这样做。
在这里的许多问答中详细讨论了它(例如:为什么我的 shell 脚本会因空格或其他特殊字符而窒息?,何时需要双引号?,shell 变量的扩展以及 glob 和 split 对其的影响,引用vs 不带引号的字符串扩展)
自从 70 年代末 Bourne shell 首次发布以来就是这种情况,并且没有被 Korn shell 改变(David Korn 最大的遗憾之一(问题 #7))或者bash大部分复制了 Korn shell,这就是POSIX/Unix 是如何指定的。
现在,我们仍然在这里看到许多答案,甚至偶尔会公开发布未引用变量的 shell 代码。你会认为人们现在已经学会了。
根据我的经验,主要有 3 类人会省略引用他们的变量:
初学者。这些可以被原谅,因为它是一种完全不直观的语法。我们在这个网站上的职责是教育他们。
健忘的人。
即使经过反复锤击也不相信的人,他们认为Bourne shell 的作者肯定没有打算让我们引用所有变量。
如果我们揭露与此类行为相关的风险,也许我们可以说服他们。
如果您忘记引用变量,那么最糟糕的事情是什么。真的有那么糟糕吗?
我们在这里谈论什么样的漏洞?
在什么情况下会出现问题?
在对最近问题的评论中,Stéphane Chazelas 提到双括号算术存在安全隐患,例如:
x=$((1-$x))
Run Code Online (Sandbox Code Playgroud)
在大多数贝壳上。
我的谷歌技能似乎生疏了,我找不到任何东西。双括号算术的安全含义是什么?
我发现的方法还通过影响换行符来进一步破坏线路。
例如...
$ message="First Line\nSecond Line";
$ echo "${message^^}"
FIRST LINE\NSECOND LINE
Run Code Online (Sandbox Code Playgroud)
是否有一种优雅的方法将字符串转换为大写,但保留转义字符,以获得以下输出?
FIRST LINE\nSECOND LINE
Run Code Online (Sandbox Code Playgroud)
我可以做一些复杂的事情,比如将“\n”更改为 0001 或类似的操作,应用转换,然后将 0001 返回到“\n”。但也许有更好的方法。
当我试图了解如何工作时,我编写了以下脚本printf:
#!/usr/bin/bash
printf "Give me your three preferences.?
"
read p1
read p2
read p3
printf "%s\n" "${p1}" "${p2}" "${p3}"
printf "Just the same as this, \n"
printf "%s\n%s\n%s\n" "${p1}" "${p2}" "${p3}"
printf "I've found this way to be the easiest, ${p1}\n ${p2}\n ${p3}\n"
Run Code Online (Sandbox Code Playgroud)
通过反复试验,我发现第三种方法是有效的 - 尽管没有指定这个学习资源。我printf最常使用这种方式,因为它echo类似于 -。是否存在这种打印值的方式stdout不起作用的变量情况或值?为什么我想避免这种使用方式printf?