SHELL与空格

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gg_18826075157/article/details/78077602

SHELL与空格

1.参数传递

众所周知,SHELL的脚本或函数调用与我们熟悉的其他编程语言有很大的不同,其中需要特别注意的就是参数传递。下面是函数/脚本调用的最一般写法:

函数名/脚本文件路径 参数1 参数2 参数3

极简的语法同时也带来一些坑,由于各参数间默认以空格作为分隔符,而我们习惯于在传递参数时省略字符串的引号。如果某一个参数本身就含有空格,那将会引发一些意想不到的错误甚至灾难。

比如,我们想切换到「Program Files」这个目录下,于是很自然地输入以下命令:

$ cd Program Files

而在SHELL看来,上面的命令是在命令它切换到「Program」这个目录下,而同时它发现了你“多传进来”的一个参数——「Files」,因为cd命令的内部实现会先检查参数数量的合法性,因此它会提醒你可能使用错误了,并终止运行。

但是,其他命令很可能发现不了这种错误,或者根本不可能检测出来,只能依靠程序员自己保证参数传递的正确性。

正确的写法可以参考下面:

$ cd "Program Files"
$ cd Program\ Files

总结一下,就是养成传递参数时为每个参数加上引号的好习惯,或者退而求其次,记得为每个字符串内的空格字符进行转义。

更一般地,对于字符串变量的取值操作都应该加上引号。

2.IFS环境变量

IFS 的全称是 Interal Field Separator ,即“内部区域分隔符”,它也是一个内置环境变量,存储着默认的文本分隔符,系统默认的分隔符包括空格、制表符(\t) 、换行符(\n) 。

下面以一个例子说明IFS如何影响我们编写SHELL脚本。

比如,我们想一行行地读取并处理某一个文本文件的内容。

$ cat datas.txt
I choose a lazy person to do a hard job.
Because a lazy person will find an easy way to do it.

然后,我们这样编写SHELL脚本:

$ cat show_lines.sh
#!bash
filename=$1
for line in `cat ${filename}`
do
  echo ${line}
done

但是,运行脚本后发现程序并没有一行行地处理文本,而是一个个单词地处理文本。

$ ./show_lines.sh datas.txt
I
choose
a
lazy
...

归其原因,是IFS仅应包括换行符,而忽略所有的空格,于是我们把SHELL脚本改写一下。

$ cat show_lines.sh
#!bash

# 保存好原来的IFS的值,方便以后还原回来
PRE_IFS=$IFS

# 设置IFS仅包括换行符
IFS=$'\n'

filename=$1
for line in `cat ${filename}`
do
  echo ${line}
done

# 任务执行完毕,把IFS还原回默认值
IFS=$PRE_IFS

再次运行脚本,这次结果就符合我们预期了。

$ ./show_lines.sh datas.txt
I choose a lazy person to do a hard job.
Because a lazy person will find an easy way to do it.

3.更加复杂的情况

比如,我们有以下两个十分简单的SHELL脚本——parent.sh和child.sh:

$ cat parent.sh
#!bash
bash $@ &

这里提示一下,$@是该脚本接收到的所有参数。

$ cat child.sh
#!bash
echo $1 > $2

我们想往「file1」文件中写入以下内容——”user01 pass01”,于是输入以下命令

$ ./parent.sh ./child.sh "user01 pass01" file1

而运行结果却是,往「pass01」文件中写入以下内容——”user01”。

归其原因,是「parent.sh」脚本中的bash $@ &在执行时会被替换为bash ./child.sh user01 pass01 file1 &

要纠正错误的话,需要这样修改「parent.sh」脚本:

$ cat parent.sh 
#!bash
bash "$@" &

此后,重新执行命令,发现跟我们预想的一样。

$ ./parent.sh ./child.sh "user01 pass01" file1
$ cat file1 
user01 pass01

这时,「parent.sh」脚本中的bash $@ &在执行时会被替换为bash "./child.sh" "user01 pass01" "file1" &

4.$*变量

在不加双引号的情况下,$*与$@作用一样。

而加上双引号后,$* 会把所有参数是为一个字符串整体,然后再把这个字符串整体用双引号括起来。

比如,我们这样修改「parent.sh」脚本:

$ cat parent.sh 
#!bash
bash "$*" &

运行命令,会惊讶地发现

$ ./parent.sh ./child.sh "user01 pass01" file1
bash: ./child.sh user01 pass01 file1: No such file or directory

因为它把”./child.sh user01 pass01 file1”最为一个参数传给bash,然后bash会把它最为一个脚本文件路径,试图把它找到,然后执行它,然而这玩意是不可能存在的,所以直接报错。

猜你喜欢

转载自blog.csdn.net/gg_18826075157/article/details/78077602
今日推荐