如果您已经关注 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 的作者肯定没有打算让我们引用所有变量。
如果我们揭露与此类行为相关的风险,也许我们可以说服他们。
如果您忘记引用变量,那么最糟糕的事情是什么。真的有那么糟糕吗?
我们在这里谈论什么样的漏洞?
在什么情况下会出现问题?
我通过运行 10 亿次循环来测试 Bash 和 Python 的速度。
$ cat python.py
#!/bin/python
# python v3.5
i=0;
while i<=1000000000:
i=i+1;
Run Code Online (Sandbox Code Playgroud)
重击代码:
$ cat bash2.sh
#!/bin/bash
# bash v4.3
i=0
while [[ $i -le 1000000000 ]]
do
let i++
done
Run Code Online (Sandbox Code Playgroud)
使用该time
命令,我发现 Python 代码只需要 48 秒即可完成,而 Bash 代码在我杀死脚本之前需要 1 个多小时。
为什么会这样?我预计 Bash 会更快。我的脚本有问题还是 Bash 使用这个脚本真的慢得多?
我想只使用 bash拆分'hello'
成h e l l o
一个数组,我可以在 sed 中做到这一点,sed 's/./& /g'
但我想知道当我不知道分隔符是什么时,如何在 Bash 中将一个字符串拆分成一个数组,或者分隔符是任何单个字符。我不认为我可以在${i// /}
没有一些创造力的情况下使用,因为分隔符是未知的,而且我认为该表达式不接受正则表达式。我尝试将 BASH_REMATCH 与 [[ string =~ ([az].).* ]] 一起使用,但它没有按我预期的那样工作。仅使用 bash 来完成某种string.split()
行为的正确方法是什么?原因是我试图在所有 bash 中编写 rev 实用程序:
while read data; do
word=($(echo $data|tr ' ' '_'|sed 's/./& /g'))
new=()
i=$((${#word[@]} - 1))
while [[ $i -ge 0 ]]; do
new+=(${word[$i]})
(( i-- ))
done
echo ${new[@]}|tr -d ' '|tr '_' ' '
done
Run Code Online (Sandbox Code Playgroud)
但是我使用了 tr 和 sed,我想知道如何正确进行拆分,然后我会将其修复为所有 bash。只是为了好玩。