vlambda博客
学习文章列表

linux基础:shell中的sh与bash区别与常用命令

一,什么是sh和bash?

#!/bin/sh是#!/bin/bash的缩减版

Linux系统中的/bin/sh本是bash的符号链接,鉴于bash过于复杂,有人把bash从NetBSD移植到Linux并更名为dash,并建议将/bin/sh指向它,以获得更快的脚本执行速度。Dash Shell比Bash Shell小的多,符合POSIX标准。


二,shell的基本用法

2.1,变量

2.1.1,变量的赋值

变量名=值    #注意赋值语句两边不能有空格,等号右边若有空格的话,需要加上引号(单引号或双引号都可以)。shell可以在变量名前加上$字符来取变量的值。

#!/bin/bashname=zhiwenage=23address="Hubei Wuhan"money='100$' echo "$name $age in $address"echo "I have $meney!"exit 0

注:单引号与双引号的用法,在单引号中,所有特殊字符都没有特殊含义;在双引号中,"$"、" ` "(反引号)、"\"有特殊含义,其余的没有特殊含义。至于反引号 " ` ",反引号中可以用来引用系统命令,其中的内容将会被优先执行,其功能与$(...)一样。


2.2.2,变量的类型

shell有四种类型的变量:用户自定义变量,环境变量,位置参数变量和预定义变量。


1)用户自定义变量:一般小写字母来命名,在当前shell中生效,也就是“局部变量”,如上面的name,age


2)环境变量:通常用大写字母做名字,环境变量可以在当前shell和这个shell的所有子shell中生效,如果环境变量写入相应的配置文件(如/etc/profile)那么这个环境变量就会在所有shell中生效。系统自带的环境变量的名字不可更改,但值可以按需更改。用户可以使用export命令中自己创建环境变量:

export 变量名=变量值 # 创建环境变量并赋值 #一些主要的系统环境变量如下:$HOME 当前用户的家目录$PATH 以冒号分隔的用来搜索命令的目录列表,决定了 shell 将到哪些目录中去寻找命令或程序$PS1 命令提示符,通常是 $ 字符,也可以自行设置$PS2 二级提示符,用来提示后续的输入,通常是 > 字符$IFS 输入域分隔符。当 shell 读取输入时,它给出用来分隔单词的一组字符,通常是空格、制表  符和换行符$0 shell 脚本的名字$# 传递给脚本的参数个数$$ shell 脚本的进程号(PID),脚本程序通常会用它来生成一个唯一的临时文件,如  /tmp/tmpfile_$$



3)位置参数变量

位置参数变量主要用来向脚本中传递参数或数据,变量名不能自定义,变量作用也是固定的,主要有以下几种位置参数变量

变量 描述
$1  $2 脚本程序的参数,分别代表程序的第一个参数,第二个参数......程序第10个以上参数需要用大括号包含如 ${10}
$* 代表命令行中的所有参数。在一个变量中将所有参数列出,各参数之间用环境变量 IFS 中的第一个字符分隔开。
$@ 和 $* 一样,也包含了命令行中的所有参数,但是不使用 IFS 环境变量,即使 IFS 为空,参数也是分开显示的

 注:$* 将所有的参数视为一个整体,而 $@ 将所有的参数分别视为单独的个体。一般来说,采用 $@ 来访问脚本程序的参数会比较好,不必担心 IFS 所设置的分隔符为空而导致各参数连在一起分不清楚。


4)预定义变量

预定义变量是在bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的,实际上,位置变量也是预定义变量的一种,除了上面介绍的,这里在介绍两个:

变量 描述
$? 保存最后一次执行的命令的返回状态。

如果$?的值为0,表示上一个命令成功执行;
如果值非0,表示上一个命令没有成功执行。

$! 用于保存后运行的最后一个进程的PID号


2.2,算术运算

shell的算术运算符与C语言里的差不多,优先级与顺序也相同。但是,由于shell中所有变量都是被看做字符串来存储的,因此,要处理算术表达式,还需要使用一些特殊手段将数值型字符串换成相应的数值

2.2.1,使用expr命令对算术表达式求值

#expr 命令将它的参数当做一个表达式来求值,可以用来进行数学运算。如下#!/bin/basha=2b=3c=`expr $a + $b` echo $cexit 0

注:输出结果为5,使用expr命令的那一行,使用的是反引号``,反引号中的内容优先执行,所以这一行代码的作用是将expr $a + $b这一表达式的执行结果赋给c。也可以使用$(...)来替代反引号:c=$(expr $a + $b)。反引号是一种比较老的语法形式,如果你希望自己写的脚本具备非常好的可移植性,那么可以使用反引号,新的脚本程序一般都使用 $(...) 来替代反引号了。


2.2.2,使用$((...))的方法对算术表达式求值

expr 虽然功能强大,在进行一些运算的时候,需要使用 \ 符来进行转义,这对于阅读代码的人来说并不友好。另一方面,expr 命令执行起来其实很慢,因为它需要调用一个新的 shell 来处理 expr 命令。好的一种做法是使用 $((...)) 扩展的方式。只需要将准备求值的表达式放在 $((...)) 的括号中即可进行简单的算术求值。且,所有支持 $(( ... )) 的shell,都可以让用户在提供变量名称时,无须前置 $ 符

#!/bin/basha=5;b=6echo $(($a + $b)) #输出11,在变量名前加上$,在shell中一般是取变量值的意思echo $((a + b)) #输出11,可见,变量前不加$也是可以的echo $((a | b)) # 输出 7 。这里的 | 是按位或操作符echo $((a || b)) # 输出 1 。这里的 || 是逻辑或操作符echo $((a & b)) # 输出 4 。这里的 & 是按位与操作符echo $((a && b)) # 输出 1 。这里的 && 是逻辑与操作符echo $((a * b)) # 输出 30echo $((a == b)) # 输出 0exit 0

2.3,使用 bash 计算器在shell脚本中进行浮点运算

安装bash 计算器 bc

#!/bin/bash val1=$(echo "scale=4;5/4" | bc)echo the value of val1 is $val1

注:输出:the value of val1 is 1.2500

2.4,shell中的条件判断命令test和[

test 命令与 [ 命令的作用其实是一样的,使用 [ 命令的时候,一般在结尾加上 ] 符号,使代码更具可读性。在使用 [ 命令时,[ 符号与被检查的语句之间应该留有空格。shell 中通常使用 test 命令来产生控制结构所需要的条件,根据 test 命令的退出码决定是否需要执行后面的代码。

2.4.1,字符串比较

str1="zhiwen"str2="wenzi" #用test命令,test语句的结果将作为if的判断条件,如果为真即条件为真,则执行if下面的语句if test "$str1" = "$str2" ;then ....fi #用[命令的话,可以这样,注意[与表达式之间要有空格if [ "$str1" != "$str2" ] ; then ....fi #-n string,如果字符串不为空则结果为真if [ -n "$str1" ] ; then ....fi #-z string,如果字符串为空(null),则结果为真if [ -z "$str1" ] ; then ....fi

注:使用字符串比较的时候,必须给变量加上引号 "  " ,避免因为空字符或字符串中的空格导致一些问题。实际上,对于条件测试语句里的变量,都建议加上双引号,能做字符串比较的时候,不要用数值比较


2.4.2,算术比较

num1=2num2=3 #expr1 -eq expr2 如果两个表达式相等,则结果为真if [ "$num1" -eq "$num2" ] ; then ...fi #expr1 -ne expr2 如果两个表达式不相等,则结果为真if [ "$num1" -ne "$num2" ] ; then ....fi #expr1 -gt expr2 如果 expr1 > expr2 ,则结果为真if [ "$num1" -gt "$num2" ] ; then ....fi #expr1 -ge expr2 如果 expr1 >= expr2 ,则结果为真 #expr1 -lt expr2 如果 expr1 < expr2,则结果为真 #expr1 -le expr2 如果 expr1 <= expr2,则结果为真 #!expr 如果表达式为假,则结果为真

注:算术比较和字符串比较之间的不同之处,字符串比较比较的是两个字符串,数字也是能组成字符串的,因此,当我们使用字符串比较的方式和数字比较的方式来比较两串数字的时候,结果会有些不同。

#!/bin/bash
val1="1" val2="001" val3="1 " # 字符串 val3 在 1 的后面还有一个空格    [ "$val1" = "$val2" ] echo $?              # 使用字符串比较,退出码为 1,说明两个字符串不相等 [ "$val1" -eq "$val2" ] echo $?              # 使用数值比较,退出码为 0,说明两个数值相等 [ "$val1" = "$val3" ] echo $?              # 退出码为 1 [ "$val1" -eq "$val3" ] echo $?              # 退出码为 0 exit 0

注:如果在编写代码时,变量没有加上双引号,上述程序的结果又会不同,仅对 val3 进行取值,将会忽略该字符串中的空格,则第三个表达式的退出码将为 0 。这也说明了在变量两边加上双引号的重要性。


2.4.3文件条件测试

文件条件测试 结果

-d file 如果文件是一个目录,则结果为真

-e file 如果文件存在,则结果为真。注意,历史上 -e 选项不可移植,所以通常使用的是 -f 选项  

-f file 如果文件存在且为普通文件,则结果为真

-g file 如果文件的 set-group-id 位被设置,则结果为真

-r file 如果文件可读,则结果为真

-s file 如果文件大小不为 0 ,则结果为真

-u file 如果文件的 set-user-id 为被设置,则结果为真

-w file 如果文件可写,则结果为真

-x file 如果文件可执行,则结果为真

#!/bin/bashif [ -f /bin/bash ] ; then echo "file /bin/bash exists"fi if [ -d /bin/bash ] ; then  echo "/bin/bash is a directory"else  echo "/bin/bash is not a directory"fi exit 0

2.5,控制结构

shell 中的控制结构与其他程序设计语言中的控制结构类似,也是由顺序结构、选择结构和循环结构组成

2.5.1,if语句

if condition1then statements1elif condition2then statements2else statements3fi

2.5.2,case语句

case variable in pattern [ | pattern ] ... ) statements;; pattern [ | pattern ] ... ) statements;; ...esac
#!/bin/bashread -p "please keyin a word:" -t 5 word case $word in [a-z] | [A-Z] ) echo "You have keyin a letter";; [1-9] ) echo "You have keyin a number";;  * ) echo "Unknow input"esac exit 0

2.5.3,for语句

for variable in valuesdo statementsdone
#!/bin/bash
for name in tongye wuhen xiaodong wufei laowang do echo $name done                                                                                        exit 0

2.5.4,while 与 until 语句

while conditiondo statementsdone
until conditiondo statementsdone
 #!/bin/bash  i=1  while [ "$i" -le 10 ]  do read -p "please keyin a number:" i done  echo "$i"  exit 0

注:这段代码从键盘中输入一个数字,直到输入数值大于 10,退出循环并打印最后输入的那个值。