这篇bash使用教程面向正在学shell脚本、又总在变量上踩坑的读者。你会读到一套不依赖特定发行版的通用排查思路:如何区分赋值与引用、单双引号各自的行为边界、以及命令替换时最容易被忽略的空白处理。具体功能以站内实际为准,建议边读边在你自己的bash环境里验证每个例子。
在bash里写name = "tom"和name="tom",前者不会报错,但bash会把name当成一个命令去执行,然后传入两个参数。这是新手最常见的静默错误——脚本继续跑,但变量是空的。判断标准很简单:等号两侧紧贴变量名和值,中间不能有空格。如果你在脚本里发现某个变量怎么都取不到值,先检查赋值语句周围有没有多余空白。另一个容易混淆的是export命令,export PATH=$PATH:/opt这种写法里等号两侧同样不能有空格。
单引号内的所有字符都按字面处理,连反斜杠都不转义;双引号内则会展开变量、命令替换和部分转义。这个区别是bash引用规则的核心。写路径或正则时,如果不想让里面的$或反引号被解释,就用单引号;如果要在字符串里插入变量值,用双引号。一个典型误区是echo '$HOME'会输出字面的$HOME,而echo "$HOME"会输出你的家目录路径。如果你拿不准某段字符串会不会被意外展开,最稳妥的做法是先用单引号包起来试跑一次。
用反引号或$(...)做命令替换时,命令输出的尾部换行符会被剥离,但内部的换行和多余空格会原样保留。比如files=$(ls)如果输出多行,$files里会包含换行符,直接echo $files看起来正常,但一旦用for循环遍历,反而会把整块输出当成一行处理。通用方法是对这类多行输出先用while IFS= read -r line逐行读取,或者用mapfile读入数组。判断标准:凡是需要逐项处理的命令输出,不要直接塞进普通变量,先想清楚它是单值还是多值。
bash里变量本质都是字符串,算术运算需要用$((...))包裹。比如a=5之后写b=$a+1,得到的b是字符串5+1而不是6。正确写法是b=$((a+1))。另一个常见坑是变量里存了带前导零的数字,比如num=08,在某些老版本bash里会被当成八进制导致报错。通用对策:涉及日期或编号的变量,要么用10#前缀强制十进制,要么先做一次字符串清洗。类型相关的坑在脚本里不容易一眼看出,建议在运算前用printf '%s\n' "$var"打印确认实际内容。
当你想把变量和固定后缀拼在一起,比如prefix="file",想得到file_2024,写成echo $prefix_2024会去读名为prefix_2024的变量,结果为空。必须用花括号明确边界:echo ${prefix}_2024。这个规则在数组下标、字符串切片、默认值替换里同样适用。如果脚本里出现多个相似变量名,写花括号能避免很多隐晦错误。还有一个关联误区:变量名大小写敏感,Name和name是两个变量,命名时统一用小写字母+下划线能减少混淆。
脚本里的$1,$2是位置参数,$@和$*都表示所有参数,但行为不同——$@会把每个参数当成独立个体,$*会把所有参数拼成一个字符串。如果参数里含有空格,不加双引号直接用$@会重新分词,导致带空格的参数被拆开。通用写法是"$@"保留每个参数的原始形态。另外$?存的是上一条命令退出码,但如果你在取它之前执行了任何赋值或echo,返回值就被覆盖了。想保留退出码,要立刻存到另一个变量里。
如果你的脚本只是三五行,不涉及外部命令输出,重点检查等号空格和单双引号;如果脚本要解析命令结果,优先处理多行输出的循环方式;如果涉及数学运算,统一用$((...))并打印确认。写完之后,用bash -n yourscript.sh做语法检查,再用bash -x跑一遍看每次展开的实际值,这个组合能覆盖大部分引用类错误。别急着一次写完长脚本,把每个变量单独赋值、单独引用、单独打印,问题会清晰很多。
先检查赋值行是否有多余空格,比如var = 123就是错的。再确认变量名没有被拼写错,尤其注意大小写。如果赋值在函数内部,还要看是否忘了用local或export导致作用域不对。最后用set -u开启未定义变量报错,能帮你快速定位。
规则是外层用双引号时,内层单引号没有特殊含义,直接写即可;外层用单引号时,内层不能再放单引号,只能通过'\''这种序列来转义。实际场景里更推荐避免嵌套,把字符串拆成相邻段落拼接,比如'abc'"$var"'def',既不用转义又保持可读。
核心做法是永远给变量加双引号:ls "$dir",而不是ls $dir。如果要把路径存进数组,用paths=("$dir1" "$dir2")。在for循环里遍历文件列表时,用find ... -print0配合while IFS= read -r -d ''能正确处理换行和空格。自己写脚本时,对任何来自外部的路径变量默认加引号,能避免大多数头疼问题。
内容更新时间:以站内最新版本为准,页面功能可能随改版调整