在Linux中,shell的重要性不言而喻。它类似于DOS下的command和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。
当我们写一个shell脚本需要指明它在那种环境下进行编译。所以在一个脚本的开始,我们需要一个称为”shebang”的类似头文件的东西。比如#!/bin/bash,表示解释器/bin/bash解释执行。
1.shell执行脚本的两种方式
在Linux中脚本的执行也是需要制定格式的。目前,我们常说的有两种。
第一种:chmod + x test.sh
这使得test.sh具有了可执行权限,然后我们通过“./”直接可以运行test.sh。
###########################################################
# File Name: test.sh
# Author: monster
# mail: 1104306242@qq.com
# Created Time: Mon 26 Jun 2017 04:05:53 PM CST
###########################################################
#!/bin/bash
echo "hello world"
这个代码非常简单,就是将“hello world”打印出来。结果如下。
第二种:/bin/bash test.sh
大家都知道在Linux下一般会考虑安全问题,所以创建一个新文件一般是没有可执行权限的。那如果我不改变权限,但我仍想要执行权限应该怎么办?这里就可以用第二种,直接指明我们需要根据什么来编译。
讲了怎么运行shell脚本,下来我们应该说说shell脚本运行的原理了。每当我们运行一个shell脚本的时候,首先是先由交互shell去fork/exec出一个子shell进程,然后由这个子shell去执行脚本,父进程bash等待子进程终止。一般的shell脚本都是这样的,但也不是一成不变的。下面这个脚本就会出现问题。
#############################################
# File Name: test.sh
# Author: monster
# mail: 1104306242@qq.com
# Created Time: Mon 26 Jun 2017 04:54:52 PM CST
##############################################
#!/bin/bash
echo "before:"
pwd
cd ..
echo "after:"
pwd
在上面的这个脚本里,按理说我们最后的目录应该是在/code目录下。我们通过在脚本下运行和bash下运行进行对比,很明显发现没有切换目录。这是什么原因呢?
在这个脚本里,子进程读取了cd .. 命令后,调用了相应的函数执行了命令,然后修改了目录,此时子进程执行完了所有的命令后终止,而bash等待子进程完成后等待输入。也就是说cd这个命令是子进程完成的,该命令影响力了子shell的pwd。但实际呢,当我们在键盘下输入这个命令的时候,是由shell直接运行的。所以由shell直接执行的命令,我们可以成为内置命令。如果这个时候,我们还希望cd命令可以按照所希望的执行,就可以在执行的时候加上“source”。这个source在这里的作用时:不会创建子shell,而是直接在交互时由bash执行命令。或者也可以用“.”。原理同上。
2.通配符
有时候我们需要对一系列的文件进行操作,这个时候就需要使用通配符。常用的通配符有‘ * ’、‘?’、‘[]’。举个例子,假如我们现在想查找以file开头的所有文件,就可以使用下列的命令: find file*
如果是“?”结尾,就意味着我们是查找最少文件结尾有一个任意字符的文件。例如:find file?查找以file开头,至少结尾有一个字符的文件。
如果我们写得命令是find file[1-4],也就是说查找以file开头,至少结尾是1-4中任意一个数字。
通配符在我们需要对符号要求的文件进行批量处理时使用,但有时候也需要注意在一些情况下,比如条件测试下通配符是不能使用的。
3.命令代换
在shell脚本中,有时候我们需要在脚本内部再去执行一些命令,如果只是把命令写出来,shell会解析成一串字符串,这个时候就需要把命令的结果提出来,然后将输出结果当前命令行中。
比如,我们想打印出当前时间。那么就需要:
Date=`date`
echo $Date
这样就能如愿打印出当前时间。同样“echo $(date)”也可以实现。那么这两个符号有区别吗?
其实是有的。看下面的脚本。
echo `echo \$MAIL`
echo "############"
echo $(echo \$MAIL)
我们的目的是输出有关MAIL的环境变量,事实上呢,我们输出的还有字符串。第一个命令确实输出了MAIL的相关信息,可最后一个如果他们是相同的意思也应该输出才对啊。很明显,这里是将$MAIL看成了字符串。
这个时候,我们在加上一个\ ,再次运行后就会发现,第三个如愿输出结果,并输出了一个“\“。
echo `echo \\$MAIL`
echo "############"
echo $(echo \\$MAIL)
接下来,我们做个测试,分别添加几个\ \在脚本中,看结果如何。
可以看出来,在上面的例子中,反引号对\本身就有一定的影响,每两个\ 可以输出一个\,而$()并不影响。总结一下:
1.反引号本身对\有转义作用,当需要输出特殊字符\ 时,我们需要用\ \来表示。
2.$()本身和\没什么关系,所以可以直接输出。
4.‘ & ”
单引号在shell脚本也是超级常见的,它们都可以用来输出字符串。实际上,它们之间也是有不同的。下面我们有一个例子说明一下。
###########################################################
# File Name: test.sh
# Author: monster
# mail: 1104306242@qq.com
# Created Time: Mon 26 Jun 2017 04:54:52 PM CST
###########################################################
#!/bin/bash
myval=100
echo '$myval \\ \` \" `date +%Y:%m:%d` $(ls -al)'
echo "###########################################"
echo "$myval \\ \` \" `date +%Y:%m:%d` $(ls -al)"
由上图可以看出,在单引号中的几乎所有内容都被认成了字符串,而在双引号中的内容按照命令依次解析执行。
在shell脚本中,常见符号就这么多,下一次我们来总结一下关于shell的语法。