其他开发工具

Linux Shell:Shell脚本常用语法整理

2021-02-10  本文已影响0人  xiaogp

摘要:LinuxShell脚本

Shell 是一个用 C语言编写的程序,它是用户使用 Linux 的桥梁,用户通过Shell访问操作系统内核的服务。

编写和运行Shell脚本

创建一个文件扩展名为 sh(sh代表shell),扩展名并不影响脚本执行

# vim aaa.sh
#!/bin/bash
echo 1

#!是一个约定的标记,置于解释器之前,/bin/bash是解释器Bash的路径
有两种运行Shell脚本的方式,一种是将Shell脚本作为sh/bash命令行参数或者解释器参数,另一种是将Shell脚本作为具有执行权限可执行文件
直接作为命令行参数运行

root@ubuntu:~# bash aaa.sh 
1

在ubuntu下sh是dash的链接,dash和bash的略有不同
将Shell脚本赋予可执行权限,使用./Shell文件名或者绝对路径Shell文件名运行

root@ubuntu:~# chmod a+x aaa.sh 
root@ubuntu:~# ./aaa.sh 
1
root@ubuntu:~# /home/gp/aaa.sh 
1
Linux文件权限详解:
linux文件权限.png
chmod修改权限

chmod修改文件权限分为三部分,对哪个用户进行修改,增加还是取消权限,增加或是取消什么权限

也可以直接使用数字模式,指定三个数字分别代表所有者,所有者组,其他用户,如果设定数字不足,先以右边为主,缺省的就是没有任何权限,即一个数字代表其他用户,两个数字代表所有者组和其他用户,直接设置数字相当于重置覆盖,不需要配合+,-使用
先用普通用户新建一个文件,文件初始对于所有者只有可读可写权限,对于其他用户和组内其他用户只有可读权限

# 新建一个文件
gp@ubuntu:~$ touch bbb.sh
gp@ubuntu:~$ ll bbb.sh
-rw-r--r-- 1 gp gp 0 2月  10 17:41 bbb.sh

增加权限,使得其他所有用户都有可执行权限,此处a可以省略,+x默认是对所有用户

gp@ubuntu:~$ chmod a+x bbb.sh
gp@ubuntu:~$ ll bbb.sh
-rwxr-xr-x 1 gp gp 0 2月  10 17:41 bbb.sh*

使用数字模式赋予文件所有用户所有权限

gp@ubuntu:~$ chmod 777 bbb.sh
gp@ubuntu:~$ ll bbb.sh 
-rwxrwxrwx 1 gp gp 0 2月  10 17:41 bbb.sh*

赋予全部权限也可以使用符号模式,使用a=rwx设定

gp@ubuntu:~$ chmod a=rwx bbb.sh
gp@ubuntu:~$ ll bbb.sh 
-rwxrwxrwx 1 gp gp 0 2月  10 17:45 bbb.sh*

取消其他用户的可写,可执行权限

gp@ubuntu:~$ ll bbb.sh gp@ubuntu:~$ chmod o-wx bbb.sh
gp@ubuntu:~$ ll bbb.sh 
-rwxrwxr-- 1 gp gp 0 2月  10 17:51 bbb.sh*

也可以直接使用数字模式,直接覆盖修改

gp@ubuntu:~$ chmod 774 bbb.sh 
gp@ubuntu:~$ ll bbb.sh 
-rwxrwxr-- 1 gp gp 0 2月  10 17:41 bbb.sh*

-R参数:以递归的方式对目前目录下所有档案子目录进行相同的权限变更,如果不加-R只有该文件夹修改,目录下的子目录权限没有修改

# 创建一个文件夹,再撞见2层子文件夹
drwxr-xr-x  3 gp gp      4096 2月  10 19:49  a/
gp@ubuntu:~$ tree a/
a/
└── aa
    └── aaa

将文件夹下和所有子文件夹都设置为777权限

gp@ubuntu:~$ chmod -R 777 a

再修改回来

gp@ubuntu:~$ chmod -R 744 a

Shell变量

定义变量

Shell是弱类型编程语言,不需要在定义变量的时候指定数据类型,默认数据类型都是字符串,Shell 支持以下三种定义变量的方式:

variable=value
variable='value'
variable="value"
使用变量

使用变量需要在变量名前面加美元符号$即可,变量名外面的花括号{ }是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,和${}类似的是$(),前者用变量值替换变量名,后者用命令执行结果替换变量名,后者还可以使用反引号。

gp@ubuntu:~/shell$ cat test.sh 
#!/bin/bash
a=qwe
b='as a'
c="se${b}"
d='se${b}'
e="se`pwd`"
f='se`pwd`'
g="se${b}aaa"
h="se$baaa"
echo $a
echo $b
echo $c
echo $d
echo $e
echo $f
echo $g
echo $h

打印结果

qwe  #没有空格tab可以不加引号
as a
seas a
se${b}  # 单引号是能使纯串,不能替换变量
se/home/gp/shell  # 命令需要加反引号``,也要使用双引号才能替换
se`pwd`
seas aaaa
se  # 没有花括号,会把后面的整个内容当成变量,但是变量找不到定义输出为空
只读变量readonly

已经赋值的变量可以直接调用变量名重新赋值修改覆盖,但是如果加了readonly修饰就是只读变量。修改会报错

gp@ubuntu:~/shell$ vim test.sh
#!/bin/bash
a=1
a=2
readonly a
a=3
echo $a
gp@ubuntu:~/shell$ ./test.sh 
./test.sh: line 5: a: readonly variable
2

第五行报错,不能重新赋值变量

删除变量unset

已经赋值的变量可以使用unset删除

gp@ubuntu:~/shell$ vim test.sh
#!/bin/bash
a=1
unset a
echo $a
gp@ubuntu:~/shell$ ./test.sh 

打印结果为空,变量已删除

Shell字符串

Shell中定义的变量默认的都是字符串形式,可以使用单引号,双引号,也可以不使用,字符串拼接可以使用以下几种方式

gp@ubuntu:~/shell$ a=123
gp@ubuntu:~/shell$ b="你好${a}"  # 你好123
gp@ubuntu:~/shell$ c="你好"$a""
gp@ubuntu:~/shell$ e='你好'$a''

可以使用${#}获取字符串长度

gp@ubuntu:~/shell$ d=${#a}
gp@ubuntu:~/shell$ echo $d  # 输出字符串长度3

可以使用索引提取子串,索引从0开始,如果超出越界了只输出到最后一个字符

gp@ubuntu:~/shell$ f=${a:1:3}
gp@ubuntu:~/shell$ echo $f  # 输出23
Shell 数组

在 Shell 中,用圆括号来表示数组,数组元素用空格符号分割开,数组只支持一维数字,不限定数组的大小,比如

gp@ubuntu:~/shell$ a=(1 2 aa 2.2 p_p)

可以使用[下标]获取数组的值,使用[*]或者[@]获取数组所有的值

gp@ubuntu:~/shell$ echo ${a[2]}  # aa
gp@ubuntu:~/shell$ echo ${a[*]}  # 1 2 aa 2.2 p_p

获取数组长度的方法和字符串一样,使用{#}

gp@ubuntu:~/shell$ echo ${#a[*]}  # 5

修改数组元素使用下标访问直接修改

gp@ubuntu:~/shell$ a[2]=cc
gp@ubuntu:~/shell$ echo ${a[*]}
1 2 cc 2.2 p_p

同理可以定义一个空数组,使用下标设定每个位置的值

vim a.sh
#!/bin/bash
a=()
a[0]=a
a[1]=b
a[2]=c
echo ${a[*]}
gp@ubuntu:~/shell$ chmod +x a.sh
gp@ubuntu:~/shell$ ./a.sh
a b c

可以使用元素的内置方法/删除元素

gp@ubuntu:~/shell$ a=(1 2 3)
gp@ubuntu:~/shell$ echo ${a[*]/2}
1 3

这个方法可以用来判断数组中是否包含某个元素

gp@ubuntu:~/shell$ if [[ ${a[*]/2} != ${a[*]} ]]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [[ ${a[*]/5} != ${a[*]} ]]; then echo 1; else echo 2; fi;
2

也可以使用=~来判断是否包含某元素

gp@ubuntu:~/shell$ if [[ ${a[*]} =~ 2 ]]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [[ ${a[*]} =~ 1 ]]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [[ ${a[*]} =~ 3 ]]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [[ ${a[*]} =~ 4 ]]; then echo 1; else echo 2; fi;
2

Shell脚本注释

对于单行注释使用#,对于多行注释使用:>>,前后增加一个任意的字符即可,比如BLOCK,!,EOF等,比如

:<<!  开始注释
代码
代码
!  终止
# vim a.sh
#!/bin/bash
a=()
a[0]=a
a[1]=b
#a[2]=c
echo ${a[*]}
a[2]=c
:<<!
a[3]=d
a[4]=e
!
echo ${a[*]}

:<<EOF
echo 测试注释
EOF
gp@ubuntu:~/shell$ ./a.sh 
a b
a b c

向Shell脚本传递外部参数

外部参数直接挂在启动Shell脚本命令的后面,多个参数用空格隔开,自带空格的变量用单引号或者双引号,在Shell脚本内使用$+索引直接访问

vim a.sh
#!/bin/bash
echo "file name is $0"
echo "first is ${1}"
echo "second is $2"
echo "thrid is $3"
gp@ubuntu:~/shell$ chmod +x a.sh
gp@ubuntu:~/shell$ ./a.sh 1 2 "3 4"
file name is ./a.sh
first is 1
second is 2
thrid is 3 4

同样可以使用$#获取传递的参数个数,$*获取所有传递进来的参数字符串

echo "params count is $#"  # params count is 3
echo "params string is $*"  # params string is 1 2 3 4

Shell运算符

Shell支持的运算符如下:

算数运算符

Bash不支持数学运算,需要使用expr运算符实现,expr写在反引号中,之后接数学运算,其中数字和符号空格隔开,expr只能针对整数字符串,对于小数等其他则报错。

gp@ubuntu:~/shell$ a=`expr 2 + 2`
gp@ubuntu:~/shell$ echo $a
4

也可以使用$[]的方式

gp@ubuntu:~/shell$ a=$[ 2 + 2 ]
gp@ubuntu:~/shell$ echo $a
4

也可以使用let关键字,let后面不需要对计算符号间留空格,let后面跟变量不需要$

gp@ubuntu:~/shell$ a=0
gp@ubuntu:~/shell$ let a++
gp@ubuntu:~/shell$ echo $a
1
gp@ubuntu:~/shell$ a=0
gp@ubuntu:~/shell$ let a=a+1
gp@ubuntu:~/shell$ echo $a
1
gp@ubuntu:~/shell$ let a=3+4
gp@ubuntu:~/shell$ echo $a
7

支持的运算符+-*/%===!=,其中乘号*需要加转义\

Shell运算符.png
gp@ubuntu:~/shell$ cat test.sh 
#!/bin/bash
a=3
b=10  # 只能对整数和字符串
c=`expr $a + $b`
echo "a+b=$c"
echo "a+b=$[ a + b]"
echo "a+b=$(expr $a + $b)"  # 使用$(expr)
echo "a+b=`expr $a + $b`"  # 使用反引号
echo "a==b?:`expr $a == $b`"
echo "a*b=`expr $a \* $b`"
echo "a%b=`expr $a % $b`"

输出计算结果

a+b=13
a+b=13
a+b=13
a+b=13
a==b?:0
a*b=30
a%b=3
比较运算符

算术比较符,使用字母配合[ ]括号,或者使用比较符配合(())双括号,在[ ]出现的一般比较符只有=!=都是用来比较字符串的,不可用于整数比较,不能出现><

gp@ubuntu:~/shell$ a=2
gp@ubuntu:~/shell$ b=1
gp@ubuntu:~/shell$ if (("$a" == "$b")); then echo 1; else echo 2; fi;
2
gp@ubuntu:~/shell$ if (("$a" > "$b")); then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [ $a -gt $b ]; then echo 1; else echo 2; fi;  # [ ]内部左右都要空一格,否则报错
1

字符串比较符

gp@ubuntu:~/shell$ a="abc"
gp@ubuntu:~/shell$ b="abc"
gp@ubuntu:~/shell$ if [[ $a == $b ]]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ b="abd"
gp@ubuntu:~/shell$ if [[ $a == $b ]]; then echo 1; else echo 2; fi;
2
gp@ubuntu:~/shell$ a=2020-12-13
gp@ubuntu:~/shell$ b=2019-12-30
gp@ubuntu:~/shell$ if [[ $a > $b ]]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ b=2021-12-30
gp@ubuntu:~/shell$ if [[ $a > $b ]]; then echo 1; else echo 2; fi;
2
布尔运算符

包含与,或,非,连接在多个表达式中间,用空格隔开,[[]][]在不同情况下语法不同,双中括号比中括号更加通用,可以防止语句错误,比如&&||><等可以出现在双中括号中,但是在单中括号内报错

布尔运算符1.png 布尔运算符2.png
其中-o||等价,-a&&等价,但是||&&必须在[[]]中使用
gp@ubuntu:~/shell$ a=5
gp@ubuntu:~/shell$ b=3
gp@ubuntu:~/shell$ if [ $a -lt $b -o $b -le 3 ]; then echo "1"; else echo "2"; fi;
1
gp@ubuntu:~/shell$ if [[ $a -lt $b || $b -le 3 ]]; then echo "1"; else echo "2"; fi;
1
# 多个条件的组合逻辑
gp@ubuntu:~/shell$ if [[ $a -lt $b || $b -le 2 || $a -ge 5 ]]; then echo "1"; else echo "2"; fi;
1

针对字符串比较

gp@ubuntu:~/shell$ if [ $a == $b -o $a == "abc" ]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [[ $a == $b || $a == "abc" ]]; then echo 1; else echo 2; fi;
1

&&||可以配合布尔值输出符号前后的变量,a && b,如果a为False输出a,否则输出b,a || b,如果a为False输出b,否则输出a

gp@ubuntu:~/shell$ [ $a -gt $b ] && echo 'a > b' || echo 'a < b';
a < b
文件测试运算符

主要有-r-w-x可读可写可执行,-s是否为空(大小为0),true代表不为空,-e是否存在,-d是否是个目录

gp@ubuntu:~/shell$ file="/home/gp/shell/test.sh"
gp@ubuntu:~/shell$ if [ -e $file ]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [ -s $file ]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [ -d $file ]; then echo 1; else echo 2; fi;
2
gp@ubuntu:~/shell$ if [ -r $file ]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [ -w $file ]; then echo 1; else echo 2; fi;
1
gp@ubuntu:~/shell$ if [ -x $file ]; then echo 1; else echo 2; fi;
1
# 撤销用户的执行权限
gp@ubuntu:~/shell$ chmod u-x test.sh 
gp@ubuntu:~/shell$ ll
total 12
drwxr-xr-x  2 gp gp 4096 2月  12 17:03 ./
drwxr-xr-x 40 gp gp 4096 2月  12 09:27 ../
-rw-r-xr-x  1 gp gp  139 2月  12 09:25 test.sh*
gp@ubuntu:~/shell$ if [ -x $file ]; then echo 1; else echo 2; fi;
2

Shell的echo和printf命令

echo和printf都是用于Shell打印变量的命令,使用printf可以输出更规则更格式化的结果。它引用于C语言的printf命令,使用printf可以指定字符串的宽度、实现左对齐(使用减符号-)、右对齐(默认的)、格式化小数输出等。

echo的单引号,双引号,反引号

单引号是纯串,双引号是变量替换,反引号是命令结果替换

gp@ubuntu:~/shell$ a=3
gp@ubuntu:~/shell$ echo "$a"; echo "ls"  # 变量替换
3
ls
gp@ubuntu:~/shell$ echo '$a'; echo 'ls'  # 纯字符串
$a
ls
gp@ubuntu:~/shell$ echo `$a`; echo `ls`  # 命令结果替换
3: command not found

test.sh
echo的转义和换行

echo -e识别转义和特殊意义的符号,如换行符、n、制表符\t、转义符\等

gp@ubuntu:~/shell$ echo 'Hello World!\n';echo "Hello World"!  
Hello World!\n
Hello World!
gp@ubuntu:~/shell$ echo -e 'Hello World!\n';echo "Hello World"!    # 识别\n
Hello World!

Hello World!

echo默认每行结尾自带\n,如果取消换行需要加-n

gp@ubuntu:~/shell$ echo 'Hello World!'; echo 'Hello World!';
Hello World!
Hello World!
gp@ubuntu:~/shell$ echo -n 'Hello World!'; echo 'Hello World!';
Hello World!Hello World!
echo的颜色输出

echo输出的字符串带有颜色和背景颜色,有固定的写法,-e[xx;xxm...\e[0m,因为要识别特殊符号,所以必须使用-e,且用双引号,详情如下图

echo颜色输出.png
gp@ubuntu:~/shell$ echo -e "my name is \e[31;45mgp\e[0m"
my name is gp
echo带有颜色.png
printf的使用

printf默认不在结尾加换行符,它不像echo一样,所以要手动加\n换号

gp@ubuntu:~/shell$ cat test.sh 
#!/bin/bash
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
gp@ubuntu:~/shell$ ./test.sh 
姓名     性别   体重kg
郭靖     男      66.12
杨过     男      48.65
郭芙     女      47.99

Shell控制语句与循环

Shell的控制流的基本语句为

if condition
then
    command1 
else
    command2
fi

或者

if condition1
then
    command1 
elif condition2
then
    command2
else
    command3
fi

也可以写成一行

if condition; then command1; else command2; fi;

举几个例子:

#!/bin/bash
# 判断数字相等
a=3
b=10
if [ $a -gt $b ]
then
    echo 'a > b'
else
    echo 'a<b'
fi

# 判断字符相等
c='123'
d="12$a"
if [ $c = $d ]
then
    echo 'c = d'
else
    echo 'c != d'
fi

# 判断数组是否包含
e=(a b c d e)
var='h'
if [[ ${e[*]} =~ ${var} ]]
then
    echo "数组包含$var"
else
    echo "数组不包含$var"
fi

# 多个判断条件
f=abc
if [[ $f = "ab" ]]
then
    echo 'f=ab'
elif [[ $f = ab* ]]
then
    echo 'f以ab开头'
else
    echo '都不是'
fi;

输出结果

gp@ubuntu:~/shell$ ./test.sh 
a<b
c = d
数组不包含h
f以ab开头

for循环

for循环的一般语法为

for var in item1 item2 ... itemN
do
    command
done
for (( ; ; ))

参考如下,循环对象为字符串,使用in作为关键字,以空格作为一个独立的循环对象之一,也可以设置+1循环设置最大停止条件for (( ; ; )),也可以对命令执行结果进行循环

gp@ubuntu:~/shell$ cat test2.sh 
#!/bin/bash
for i in 0 1 2 3
do
    echo "当前值为$i"
done
j=10
for (( i=5; i<=$j; i++ ))
do
    echo "当前值为$i"
done
for i in `ls`
do
    echo "当前值为$i"
done
gp@ubuntu:~/shell$ ./test2.sh 
当前值为0
当前值为1
当前值为2
当前值为3
当前值为5
当前值为6
当前值为7
当前值为8
当前值为9
当前值为10
当前值为test2.sh
当前值为test.sh

for循环对数组元素进行循环

gp@ubuntu:~/shell$ cat test2.sh 
#!/bin/bash
a=( a b c d )
for i in ${a[*]}
do 
    echo "当前元素是$i"
done
for i in ${a[@]}
do
    echo "当前元素是$i"
done
gp@ubuntu:~/shell$ ./test2.sh 
当前元素是a
当前元素是b
当前元素是c
当前元素是d
当前元素是a
当前元素是b
当前元素是c
当前元素是d

while循环

while循环的基本用法如下

while condition
do
    command
done

实例参考如下,使用let改变每次循环的状态作为停止判断条件,let操作的变量不需要使用$

gp@ubuntu:~/shell$ cat test3.sh 
#!/bin/bash
a=1
while (( $a <= 3))
do
    echo "当前值是$a"
    let a++
done
gp@ubuntu:~/shell$ ./test3.sh 
当前值是1
当前值是2
当前值是3

可以使用(())双括号作为判断条件,或者使用单中括号使用专用的判断符号

#!/bin/bash
a=1
while [ $a -le 3 ]
do
    echo "当前值是$a"
    let a++
done
echo $a

输出如下

当前值是1
当前值是2
当前值是3
4

可以使用while实现死循环

#!/bin/bash
while true
do
    echo 1
done

until循环

until循环和while循环相反,当条件为False时执行循环,为True跳出循环

gp@ubuntu:~/shell$ cat test3.sh 
#!/bin/bash
a=0
until (( $a >= 3))
do 
    echo "当前值为$a"
    let a++
done
gp@ubuntu:~/shell$ ./test3.sh 
当前值为0
当前值为1
当前值为2

break和continue跳出循环

break结束这个循环,continue跳出本次循环

gp@ubuntu:~/shell$ cat test4.sh 
#!/bin/bash
for i in 1 2 4 5 6
do
    if (( $i > 4 ))
    then
        break
    fi 
    echo $i
done
echo --------------
for i in 2 4 1 10 3
do
    if (( $i > 4 ))
    then 
    continue
    fi
    echo $i
done
    
    
gp@ubuntu:~/shell$ ./test4.sh 
1
2
4
--------------
2
4
1
3

Shell函数

上一篇下一篇

猜你喜欢

热点阅读