shell脚本基本语法
我们都知道,在编写shell脚本的时候第一行必然是#!/bin/bash因为linux中不只有bash一个解析器,不同解析器中的语法不相同,这个是通知系统使用bash解析器
一、shell脚本中的变量
shell中一样可以对变量进行赋值、运算但是需要注意几个点:
1、shell脚本相比C语言有一个优势是变量不需要定义,在使用的时候直接a=1,第一次使用就默认会定义。
2、shell中的变量只有两种类型,整型和字符串。
3、shell中使用变量不能加空格,否则会被识别成命令。
shell脚本中给变量赋值直接写即可,也不需要分号,例
a=2
b=3
c=“this is a test”
但是当使用或者输出的时候则需要前面加一个$符号,另外做加减乘除运算的时候还需要再加两层小括号,还有一些调用是需要花括号的,例
d=$((a+b))
e=$((a-b))
f=$((a*b))
g=$((a/b)) #取整
h=$((a%b)) #取余
i=$((a**3))#a的三次方
echo $c
echo "a = "$a #输出a的值
echo "b = "$b #输出b的值
echo "a+b = "${d} #输出a+b的值
echo "a-b = "${e} #输出a-b的值
echo "a**b = "${f} #输出a*b的值
echo "a/b = "${g} #输出a/b的值
echo "a%b = "${h} #输出a%b的值
echo "a^3 = "${i} #输出a的3次方的值
echo "a+b = "$((a+b)) #输出a+b的值
echo "a-b = "$((a-b)) #输出a-b的值
echo "a*b = "$((a*b)) #输出a*b的值
echo "a/b = "$((a/b)) #输出a/b的值
echo "a%b = "$((a%b)) #输出a%b的值
echo "a^3 = "$((a**3)) #输出a的3次方的值
echo $((a+b*a-b/a+a%b+a**2)) #表达式可以很长
有一个小的要注意的点,就是在shell中一行后面加注释的话井号前面要加空格。
把上面的内容写到脚本中看一下运行结果:
在ubuntu上运行脚本,使用sh命令:
forlinx@forlinx:~$ sh shell_test.sh
shell_test.sh: 18: shell_test.sh: arithmetic expression: expecting primary: "a**3"
会有一个a**3报错,这不不是语法问题,由于 是 bash
函数,在 dash
里还没声明,Debian
和Ubuntu
默认用dash
作为/bin/sh
的解释器,所以报错。
那么我们换bash命令来执行:
forlinx@forlinx:~$ bash shell_test.sh
hello world !
a = 2
b = 3
a+b = 5
a-b = -1
a**b = 6
a/b = 0
a%b = 2
a^3 = 8
a+b = 5
a-b = -1
a*b = 6
a/b = 0
a%b = 2
a^3 = 8
13
可以看到执行结果没有问题,脚本的执行还有一种方式就是./这个是我们常用的,但是这种就需要你的脚本有可执行权限,用sh命令或者bash命令就不需要。
forlinx@forlinx:~$ ./shell_test.sh
bash: ./shell_test.sh: Permission denied
另外提一点,如果你的字符串是一整个,比如hello_world!,复制的时候可不加引号,当然加了也不会有问题。
二、shell脚本中的变量表达式
表达式及含义:
KaTeX parse error: Expected '}', got '#' at position 2: {#̲string} 计算string的长度
${string:pos}从第pos个位置开始提取字符串
${string:pos:len}从第pos个位置开始提取长度为len的字符串
${string#substr}从开头删除最短匹配子串
${string##substr}从开头删除最长匹配子串
${string%substr}从最后删除最短匹配子串
${string%%substr}从最后删除最长匹配子串
例:
#!/bin/bash
str="a b c d e f g h i j"
echo "the source string is "${str} #源字符串
echo "the string length is "${#str} #字符串长度
echo "the 6th to last string is "${str:5} #截取从第五个后面开始到最后的字符
echo "the 6th to 8th string is "${str:5:2} #截取从第五个后面开始的2个字符
echo "after delete shortest string of start is "${str#a*f} #从开头删除a到f的字符
echo "after delete widest string of start is "${str##a*} #从开头删除a以后的字符
echo "after delete shortest string of end is "${str%f*c} #从结尾删除f到c的字符
echo "after delete widest string of end is "${str%%*c} #从结尾删c前面的所有字符包括c
然后我们执行一下,看一些这个截取规则:
forlinx@forlinx:~$ bash shell_test.sh
the source string is a b c d e f g h i j a b c
the string length is 25 这个长度是包括空格的
the 6th to last string is d e f g h i j a b c
the 6th to 8th string is d
after delete shortest string of start is d e f g h i j a b c可以看到a到c这个只截取了一次
after delete widest string of start is
after delete shortest string of end is a b c d e
after delete widest string of end is
三、shell中的判断式
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。
针对数值:
参数 | 说明 |
---|---|
-eq | 等于则为真 |
-ne | 不等于则为真 |
-gt | 大于则为真 |
-ge | 大于等于则为真 |
-lt | 小于则为真 |
-le | 小于等于则为真 |
比如
num1=100
num2=100
if test $[num1] -eq $[num2]
then
echo '两个数相等!'
else
echo '两个数不相等!'
fi
针对字符串:
参数 | 说明 |
---|---|
= | 等于则为真 |
!= | 不相等则为真 |
-z 字符串 | 字符串的长度为零则为真 |
-n 字符串 | 字符串的长度不为零则为真 |
num1="ru1noob"
num2="runoob"
if test $num1 = $num2
then
echo '两个字符串相等!'
else
echo '两个字符串不相等!'
fi
针对文件:
参数 | 说明 |
---|---|
-e 文件名 | 如果文件存在则为真 |
-r 文件名 | 如果文件存在且可读则为真 |
-w 文件名 | 如果文件存在且可写则为真 |
-x 文件名 | 如果文件存在且可执行则为真 |
-s 文件名 | 如果文件存在且至少有一个字符则为真 |
-d 文件名 | 如果文件存在且为目录则为真 |
-f 文件名 | 如果文件存在且为普通文件则为真 |
-c 文件名 | 如果文件存在且为字符型特殊文件则为真 |
-b 文件名 | 如果文件存在且为块特殊文件则为真 |
用于判断的命令:&&和||
&&后面的是当前面为真时执行,||前面命令执行为假时执行
这里以test命令为例,也可以和其他命令搭配
echo "Please input a filename: "
read filename
test -f $filename && echo "the file is ordinary file" || echo "the file is not ordinary file"
test -d $filename && echo "the file is document folder" || echo "the file is not document folder"
test -r $filename && echo "the file can read" || echo "the file can not read"
test -w $filename && echo "the file can write" || echo "the file can not write"
test -x $filename && echo "the file can executable" || echo "the file can not executable"
测试:
forlinx@forlinx:~$ touch test
forlinx@forlinx:~$ bash shell_test.sh
Please input a filename:
test
the file is ordinary file
the file is not document folder
the file can read
the file can write
the file can not executable
四、shell条件分支结构语句
单分支:
if 条件;then
结果
fi
双分支:
if 条件;then
结果1
else
结果2
fi
多分支:
if 条件1;then
结果1
elif条件2;then
结果2
.....
else
结果n
fi
在C语言中这种判断很多的情况下一般都会用switch case来代替,shell中也可以,不同的是不需要switch
#! /bin/sh -
name=`basename while 条件
do
结果
done
.sh`
case in读入脚本执行时候传入的第一个参数
s|start) |代表或
echo "start..."
;;两个分号等同于break
stop)
echo "stop ..."
;;
reload)
echo "reload..."
;;
*)型号和c语言中的default是一样的作用
echo "Usage: $name [start|stop|reload]"
exit 1
;;
esac
exit 0
五、循环语句
c语言中循环无非就是for、while、until
shell中也一样,小有区别
while格式
eg: ls /[eh][to][cm]*
相当于执行 ls /etc /home(若有/eom目录,就相当于会执行ls /etc /home /eom)
注:在mkdir命令下不能扩展
列出6q和6dl涉及的所有设备树文件
forlinx@forlinx:~/linux/linux-4.1.15/arch/arm/boot/dts$ ls imx6{q,dl}-[cs]*
imx6dl-c-sabresd-4_3lcd.dts imx6dl-s2-sabresd-newlcd.dts imx6q-c-sabresd-btwifi.dts imx6q-s3-sabresd-4_3lcd.dts
imx6dl-c-sabresd-btwifi.dts imx6dl-s3-sabresd-4_3lcd.dts imx6q-c-sabresd.dtb imx6q-s3-sabresd-btwifi.dts
imx6dl-c-sabresd.dtb imx6dl-s3-sabresd-btwifi.dts imx6q-c-sabresd.dts imx6q-s3-sabresd.dtb
imx6dl-c-sabresd.dts imx6dl-s3-sabresd.dtb imx6q-c-sabresd-enetirq.dts imx6q-s3-sabresd.dts
imx6dl-c-sabresd-enetirq.dts imx6dl-s3-sabresd.dts imx6q-c-sabresd-hdcp.dts imx6q-s3-sabresd-enetirq.dts
imx6dl-c-sabresd-hdcp.dts imx6dl-s3-sabresd-enetirq.dts imx6q-c-sabresd-hdmi.dts imx6q-s3-sabresd-hdcp.dts
imx6dl-c-sabresd-hdmi.dts imx6dl-s3-sabresd-hdcp.dts imx6q-c-sabresd-ldo.dts imx6q-s3-sabresd-hdmi.dts
imx6dl-c-sabresd-ldo.dts imx6dl-s3-sabresd-hdmi.dts imx6q-c-sabresd-lvds.dts imx6q-s3-sabresd-ldo.dts
imx6dl-c-sabresd-lvds.dts imx6dl-s3-sabresd-ldo.dts imx6q-c-sabresd-mipi.dts imx6q-s3-sabresd-lvds.dts
imx6dl-c-sabresd-mipi.dts imx6dl-s3-sabresd-lvds.dts imx6q-c-sabresd-newlcd.dts imx6q-s3-sabresd-newlcd.dts
imx6dl-c-sabresd-newlcd.dts imx6dl-s3-sabresd-newlcd.dts imx6q-cubox-i.dts imx6q-sabreauto.dts
imx6dl-cubox-i.dts imx6dl-sabreauto.dts imx6q-s2-sabresd-btwifi.dts imx6q-sabreauto-ecspi.dts
imx6dl-s2-sabresd-btwifi.dts imx6dl-sabreauto-ecspi.dts imx6q-s2-sabresd.dts imx6q-sabreauto-enetirq.dts
imx6dl-s2-sabresd.dts imx6dl-sabreauto-enetirq.dts imx6q-s2-sabresd-enetirq.dts imx6q-sabreauto-flexcan1.dts
imx6dl-s2-sabresd-enetirq.dts imx6dl-sabreauto-flexcan1.dts imx6q-s2-sabresd-hdcp.dts imx6q-sabreauto-gpmi-weim.dts
imx6dl-s2-sabresd-hdcp.dts imx6dl-sabreauto-gpmi-weim.dts imx6q-s2-sabresd-hdmi.dts imx6q-sabrelite.dts
imx6dl-s2-sabresd-hdmi.dts imx6dl-sabrelite.dts imx6q-s2-sabresd-ldo.dts imx6q-sbc6x.dts
imx6dl-s2-sabresd-ldo.dts imx6q-cm-fx6.dts imx6q-s2-sabresd-lvds.dts
imx6dl-s2-sabresd-lvds.dts imx6q-c-sabresd-4_3lcd.dts imx6q-s2-sabresd-newlcd.dts
until格式相同,不同的就是while当条件为真时执行,until当条件为假的时候执行
另外shell中也能使用函数,数组等,这些内容就不细说了,有兴趣百度上可以查到很多。
六、特殊字符用法
说一下shell中的一些特殊用法:除了$(())求值之外,还有遇到的一些:
{}大括号作用1:通配符扩展,例如
ls my_{finger,toe}s
这个命令相当于ls my_fingers my_toes
mkdir {userA,userB,userC}-{home,bin,data}
我们将得到 userA-home, userA-bin, userA-data, userB-home, userB-bin,userB-data,userC-home, userC-bin, userC-data,这几个目录。
列出6q-c和6dl-c涉及的所有设备树文件:
forlinx@forlinx:~/linux/linux-4.1.15/arch/arm/boot/dts$ ls imx6{q,dl}-c-*
imx6dl-c-sabresd-4_3lcd.dts imx6dl-c-sabresd-hdcp.dts imx6dl-c-sabresd-newlcd.dts imx6q-c-sabresd-enetirq.dts imx6q-c-sabresd-mipi.dts
imx6dl-c-sabresd-btwifi.dts imx6dl-c-sabresd-hdmi.dts imx6q-c-sabresd-4_3lcd.dts imx6q-c-sabresd-hdcp.dts imx6q-c-sabresd-newlcd.dts
imx6dl-c-sabresd.dtb imx6dl-c-sabresd-ldo.dts imx6q-c-sabresd-btwifi.dts imx6q-c-sabresd-hdmi.dts
imx6dl-c-sabresd.dts imx6dl-c-sabresd-lvds.dts imx6q-c-sabresd.dtb imx6q-c-sabresd-ldo.dts
imx6dl-c-sabresd-enetirq.dts imx6dl-c-sabresd-mipi.dts imx6q-c-sabresd.dts imx6q-c-sabresd-lvds.dts
另外提一句,这些在脚本中和命令行中执行都是一样的。
用法二:可用于语句块的构造,语句之间用回车隔开。
如果你想在某些使用单个语句的地方(比如在AND或OR列表中)使用多条语句,你可以把它们括在花括号{}中来构造一个语句块。
这个用法和C语言一样
用法三:参数扩展
和$搭配使用,前面多次用到了
[] 中括号:**用法一:通配符扩展:
**允许匹配方括号中任何一个单个字符
双引号:如果想在定义的变量中加入空格,就必须使用单引号或双引号,
单、双引号的区别在于双引号转义特殊字符而单引号不转义特殊字符
eg: $ heyyou=home
$ echo ‘$heyyou'
$ $heyyou ($没有转义)
eg: $ heyyou=home
$ echo “$heyyou”
$ home (很明显,$转义了输出了heyyou变量的值)
**用法二:用于条件判断符号:
**
[]符号可理解为指向test命令的一个软链接,所以其用法可完全参照test,将test位置替换为[便可。
eg: if [ "$?" != 0 ] 等价于 if test “$?” != 0
then echo “Executes error”
**‘string’ 单引号 和 “string” 双引号 **
${待测变量:=默认值}
${:=}
${待测变量:-默认值}
当待测的变量不存在或者为空时,将直接把待测变量设置为默认值(赋值),如果待测变量存在,则直接传变量值。
是在待测的变量不存在或者为空时临时返回默认值,并不是对变量赋值。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)