Shell单词分割引起的问题
12/08
本文最后更新于
2023年12月08日,已超过
449天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!
前文介绍shell几种展开,其中单词分割展开容易引起意想不到的问题。我们来看两个例子加深下理解。
示例1
前文提到的脚本示例:
#!/bin/bash
num_files=0
for file in ~/sample/*.txt
do
echo $file
num_files=$((num_files + 1))
done
echo num of files is $num_files
我们使用echo $file
打印出每个文件名,这里的$file
没有加上双引号,会进行单词分割展开,如果只是单纯打印到屏幕,问题不大。
但假如我们需要对每个文件进行处理,比如将每个文件内容追加到同一个文件total.txt里:
#!/bin/bash
> total.txt
for file in ~/sample/*.txt
do
echo $file
cat $file >> total.txt
done
脚本执行信息:
/home/user/sample/a.txt
/home/user/sample/b c.txt
cat: /home/user/sample/b: No such file or directory
cat: c.txt: No such file or directory
/home/user/sample/d.txt
原因在于前文所说的单词分割展开。由于$file
未加双引号,/home/user/sample/b c.txt
分割成两个单词,但目录下没有这两个文件,cat命令执行会输出”No such file or directory“。
解决方法:使用双引号禁止单词分割展开cat "$file"
。
实际上,以上脚本可以用一行代码代替cat ~/sample/*.txt > total.txt
。
示例2
比如多行字符串输出,如下所示
$ lines="line1
> line2
> line3"
$ echo $lines
line1 line2 line3
$ echo "$lines"
line1
line2
line3
$lines
加不加引号,echo返回的结果是不同的。如果不加引号,多行字符串中间换行符变成了空格;而加上双引号输出,得到与原有相同的结果。
造成结果差异的原因在于shell的单词分割(word splitting)处理,单词如何分割由变量IFS值决定的,IFS分割默认字符包含<空格><Tab><换行符>
三个。因此如果没有双引号,多行字符串内部的换行符会变成空格。
echo显示单词分割后的结果,以空格分割多个参数。
试验改变IFS变量值后echo显示结果:
$ IFS="" # 空分隔符,不包含换行符
$ echo $lines
line1
line2
line3
$ IFS="\i" #字符i作为分隔符
$ echo $lines
l ne1
l ne2
l ne3
所以为了避免shell的单词分割处理,变量展开建议使用双引号括起来"$var"
。

