shell 编程(二):语法结构 - 基础


shell 语法结构(基础部分)

一、变量

shell 作为一种编程语言来说肯定是会有变量的定义的,但是却不同于一般的编程语言,shell对于变量的定义具有严格的格式限制。

  • 所有的变量名必须为大写
  • 变量名中只可以出现下划线
  • 变量定义分为环境变量和本地变量
  • 变量定义时等号左右没有空格(有空格会被当作命令和参数执行)

1.环境变量

环境变量是可以由父进程传递给子进程的,因此 shell 进程中的环境变量可以从当前 shell 进程传给 fork 出来的子进程。

使用下面的命令可以显示当前 shell 进程中所有的环境变量:

$ printenv

2.本地变量

本地变量只能存在于当前 shell 进程中。

使用下面的命令可以显示当前 shell 进程中所定义的所有变量(包括本地变量和环境变量)和函数:

$ set

环境变量是任何进程都有的概念,而本地变量是 shell 特有的概念。

3.定义变量

在 shell 中,环境变量和本地变量的定义和用法基本一致。

在 shell 中定义或赋值一个本地变量:

$ VARNAME=value

该变量被定义好之后只是一个普通的本地变量,可以使用如下的命令将本地变量导出为环境变量:

$ export VARNAME

通常定义和导出环境变量可以一步完成:

$ export VARNAME=value

4.删除变量

使用如下的命令来删除一个本地变量或者环境变量:

$ unset VARNAME

5.获取变量的值

在 shell 中获取一个变量的时候不能直接用变量名,而是使用用 ${VARNAME}来表示它的值,也可以简写为 $VARNAME :

echo $VARNAME

注意:

  • 在定义变量时不用 $ ,取变量值时要用 $ 。
  • 和 C 语言不同的是,shell 变量不需要明确定义类型。(事实上 shell 变量的值都是字符串,比如我们定义VAR=45,其实VAR的值是字符串45而非整数)
  • shell 变量不需要先定义后使用,如果对一个没有定义的变量取值,则值为空字符串。

二、文件名代换(Globbing)

在 shell 脚本中也是可以使用一些 通配符(Wildcard) 来匹配字符串的,shell 所支持的通配符如下:

  • *:匹配0个或多个任意字符
  • ?:匹配一个任意字符
  • [若干字符]:匹配方括号中任意一个字符的一次出现

其实这些通配符也就是正则表达式,可以实现对某一类字符串进行匹配。

$ ls /dev/ttyS*
$ ls ch0?.doc
$ ls ch0[0-2].doc
$ ls ch[012]   [0-9].doc

注意,Globbing 所匹配的文件名是由 shell 展开的,也就是说在参数还没传给程序之前已经展开了,比如上述 ls ch0[012].doc 命令,如果当前目录下有 ch00.doc 和 ch02.doc,则传给 ls 命令的参数实际上是这两个文件名,而不是一个匹配字符串。

三、命令代换

如何在定义变量的时候将一个某个命令的执行结果赋值给该命令呢?

其实,由 ` 反引号括起来的是一条命令,shell 先执行该命令,然后将输出结果立刻代换到当前命令行中。

例如定义一个变量存放 date 命令的输出:

$ DATE=`date`
$ echo $DATE

命令代换也可以用 $() 表示:

$ DATE=$(date)

四、算术代换

1.加减乘除运算

算术运算法 $(()) 用于进行算术计算,$(()) 中的 shell 变量取值将转换成整数,同样含义的 $[] 等价例如:

$ VAR=45
$ echo $(($VAR+3))

$(()) 中只能用 +-*/ 和 () 运算符,并且只能做整数运算。

2.进制表示

$[base#n],其中base表示进制,n 按照 base 进制解释,后面再有运算数,按十进制解释。

echo $[2#10+11]
echo $[8#10+11]
echo $[10#10+11]

五、转义字符

和 C 语言类似,\ 在 shell 中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义(回车除外),换句话说,紧跟其后的字符取字面值。例如:

$ echo $SHELL
# /bin/bash
$ echo \$SHELL
# $SHELL
$ echo \\
\

比如创建一个文件名为“$ $”的文件可以这样:

$ touch \$\ \$

还有一个字符虽然不具有特殊含义,但是要用它做文件名也很麻烦,就是 - 号。如果要创建一个文件名以-号开头的文件,这样是不行的:

$ touch -hello
# touch: invalid option -- h
# Try `touch --help' for more information.

# 即使加上\转义也还是报错:

$ touch \-hello
# touch: invalid option -- h
# Try `touch --help' for more information.

这是因为各种 UNIX 命令都把 - 号开头的命令行参数当作命令的选项,而不会当作文件名。如果非要处理以-号开头的文件名,可以有两种办法:

$ touch ./-hello

或者

$ touch -- -hello

\ 符号其实还有一种用法,在\后敲回车表示续行,Shell并不会立刻执行命令,而是把光标移到下一行,给出一个续行提示符>,等待用户继续输入,最后把所有的续行接到一起当作一个命令执行。例如:

itcast$ ls \
> -l
# (ls -l命令的输出)

六、引号

1.单引号

和 C 语言不一样,shell 脚本中的单引号和双引号一样都是字符串的界定符,而不是字符的界定符。

单引号用于保持引号内所有字符的字面值,即使引号内的\和回车也不例外,但是字符串中不能出现单引号。如果引号没有配对就输入回车,shell 会给出续行提示符,要求用户把引号配上对。例如:

$ echo '$SHELL'
# $SHELL
$ echo 'ABC\(回车)
> DE'
# (再按一次回车结束命令)
# ABC\
# DE

2.双引号

被双引号用括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。这点与单引号的处理方式不同

$ DATE=$(date)
$ echo "$DATE"
# $DATE
$ echo '$DATE'
# Sun Mar 31 12:37:40 UTC 2019

注意:单引号和双引号一定得分清楚,双引号中引的命令的话是会被展开的,而单引号则直接表示为字面值