Linux——四、Shell脚本


shell变量相关知识可以先看 https://blog.csdn.net/weixin_43696529/article/details/119849273?spm=1001.2014.3001.5501

一、编写与执行

[root@bogon shell]# cat hello.sh
#!/bin/bash
echo 'hello'

如上是一个最简单的shell脚本。每个shell脚本第一行必须是#!/bin/bash,第二行开始就可以编写shell脚本代码了,这里只输出一个hello

执行方式

最常用的执行方式:

  • sh shell_script.sh

    [root@bogon shell]# sh hello.sh
    hello
    
  • ./shell_script.sh

    [root@bogon shell]# ./hello.sh
    -bash: ./hello.sh: 权限不够
    

    哦豁权限不够,使用./script_name时脚本必须有可执行权限

    [root@bogon shell]# chmod +x hello.sh
    [root@bogon shell]# ll hello.sh
    -rwxr-xr-x. 1 root root 25 828 16:48 hello.sh
    [root@bogon shell]# ./hello.sh
    hello
    

    这样就可以执行了

  • source

    [root@bogon shell]# source hello.sh
    hello
    

    没什么区别好像。

    但是和其他方式不同的是,source是在当前bash进程中执行,其他方式是开启一个子bash执行脚本,那么也就是说,假如脚本中定义了变量,那么在执行完毕后,使用source的方式可以把变量保留在当前进程,而其他方式在执行完后相关变量也就没有了。

    #!/bin/bash
    echo 'hello'
    test_name="xys"
    echo $test_name
    

    如上,定义了一个test_name变量,下面分别采用两个方式执行脚本:

    [root@bogon shell]# sh hello.sh
    hello
    xys
    # 执行完后无法在当前进程获取到变量
    [root@bogon shell]# echo $test_name
    
    [root@bogon shell]# source hello.sh
    hello
    xys
    # source执行完后,可以在当前进程获取到变量
    [root@bogon shell]# echo $test_name
    xys
    

二、运算符、判断以及流程控制

基本运算符

支持:+ - * / % = == !=

< > <= >=,不可直接使用,需要使用下面的关系运算符

运算时,要使用expr:

[root@localhost shell]# echo `expr 1 + 2 `
3

注意:expr 1 + 2 之间要有空格

2.1 test

test [选项] expression,其实就是测试表达式是否正确,正确返回True,否则返回False

2.1.1 文件名【文件类型】测试

有以下选项【都是判断文件名是否存在,但是类型不同】:

选项作用
-e文件名是否存在
-f文件名是否存在且为文件
-d文件名是否存在且为目录
-b…block device设备
-ccharacter device设备
-Ssocket文件
-pFIFO文件
-L链接文件
2.1.2 文件权限测试
选项作用
-r是否有可读权限
-w…写权限
-x可执行权限
-uSUID属性
-gSGID属性
-kSticky bit属性
-s是否存在,且为非空文件
2.1.3 文件比较

test file1 -[nt、ot、ef] file2

-ntnewer than file1比file2新
-otolder than file1比file2旧
-ef两个文件是否为同一文件【硬链接的判定】
2.1.4 关系运算符

test num1 -[选项] num2

[root@localhost shell]# test 1 -eq 2 && echo "true" || echo "fasle"
fasle
选项作用
-eq相等
-ne不等
-gt大于
-lt小于
-ge大于等于
-le小于等于
2.1.5 字符串运算符
选项作用
-z stringstring是否为空
-n stringstring是否非空
s1==s2是否相等
s1!=s2是否不等…
2.1.6 逻辑【布尔】运算
  • -a

    就是and(&&),test -z str1 -a str1==str2,-a两侧表达式都成立才返回True

  • -o

    就是or ( || )

  • !

除了文件比较,其他就是等同于我们基本的运算和逻辑运算符,只不过这里是test中的表达方式。

下面脚本捡几个常用的试试:

test脚本例子
#!/bin/bash

# 输入一个文件名
read -p 'input filename to test:' filename
# 文件存在则输出要测试的文件名否则输出文件错误并退出
test -z ${filename} && 'please input a valid filename' && exit 0 || echo "then will test file->${filename}"

#文件是否存在并判定是否为文件或目录
test -e ${filename} -a -f ${filename} && echo "${filename} 存在且为文件"
test -e ${filename} -a -d ${filename} && echo "${filename} 文件存在且为目录"
# 权限监测
test -r ${filename} && echo "有可读权限"
test -w ${filename} && echo "${filename} 有可写权限"
test -x ${filename} && echo "有可执行权限"

#读取第二个文件
read -p "input another file to compare new or old : " filename2
test -z ${filename} && 'please input a valid filename' && exit 0 || echo "then will compare file->${filename} and ${filename2}"

# 两个文件新旧比较
test  ${filename} -nt  ${filename2} && echo "${filename}${filename2}新" || echo "${filename}${filename2} 旧"

执行:

有三个文件,file1和file2为文件,dir1为目录,创建时间如下:

drwxr-xr-x. 2 root root   6 828 18:18 dir1
-rw-r--r--. 1 root root   0 828 17:50 file1
-rw-r--r--. 1 root root   0 828 17:59 file2

1.先输入file1,再和file2比较

[root@localhost shell]# sh test_script.sh
input filename to test:file1
then will test file->file1
file1 存在且为文件
有可读权限
file1 有可写权限
input another file to compare new or old : file2
then will compare file->file1 and file2
file1 比 file2 旧

2.先输入dir1,再和file2比较

[root@localhost shell]# sh test_script.sh
input filename to test:dir1
then will test file->dir1
dir1 文件存在且为目录
有可读权限
dir1 有可写权限
有可执行权限
input another file to compare new or old : file2
then will compare file->dir1 and file2
dir1比file2新

2.2 [] 判断

[] 作用也是用来处理判断的。

[root@localhost shell]# str="xys"
[root@localhost shell]# [ "${str}" == "xys" ]
[root@localhost shell]# echo $?
0

以上,判断str变量是否等于xys,通过$?可知返回True没有错误

在中括号内,每组符号之间都需要添加空格,否则格式错误。

test中介绍的bash中的一些比较方式这里也适用,包括后面使用if判断也一样,因为都是bash命令嘛,test、[]以及if 都只是一种判断方式而已。

以下:判断file2是否比file1新,返回0是。

[root@localhost shell]# [ "file2" -nt "file1" ] && echo $?
0

2.3、默认变量

变量作用
$0脚本名
$1、$2、 3..... 3..... 3.....N第1到N个参数值
$@所有参数
$*也是所有参数,不过默认以空格分隔
$#参数个数
$$脚本运行的当前进程号
$?前一个命令的执行结果 0:无错误 1:有错误

以下脚本分别打印以上变量:

#!/bin/bash

echo "'\$1':${1}"
echo "'\$2':${2}"
echo "'\$3':${3}"
echo "'\$0':${0}"
echo "'参数个数\$#':${#}"
echo "'\$@':${@}"
echo "'\$*':${*}"
echo "'\$$':${$}"

执行:

[root@localhost shell]# sh variable.sh a b c
'$1':a
'$2':b
'$3':c
'$0':variable.sh
'参数个数$#':3
'$@':a b c
'$*':a b c
'$$':7785
shift

这个东西可以让变量偏移N个,即去掉前面N个变量:

#!/bin/bash

echo "变量:${@}"
shift 2
echo "变量:${@}"
shift 1
echo "变量:${@}"

执行:

[root@localhost shell]# sh variable2.sh 1 2 3 4 5 6
变量:1 2 3 4 5 6
变量:3 4 5 6
变量:4 5 6

2.4 if

前面的test和中括号[]判断的方式只能处理条件比较少的,当条件多或要进行多次比较时还是比较麻烦的,所以还是用if流程来处理吧:

语法如下:

if [ 条件1 ];  then
elif [ 条件2 ] && [ 条件3 ]; then
else [ 条件4 ]; then
fi

(看起来好像是python和lua的结合体哈)

fi和lua中的end一样,表示当前if流程结束。

这样就可以快乐的搭配bash相关的命令进行脚本编写了。

#!/bin/bash

if  [ "$#" -lt 2 ]; then
	echo "input at least two param" && exit 0
fi
if [ $1 -lt 10 ];then
	echo "$1 < 10"
elif [ $1 -ge 10 ] && [ $1 -lt 20 ]; then
	echo "$1 between 10 and 20"
elif [ $1 -ge  20 ] && [ $1 -lt 30 ]; then
	echo "$1 between 20 and 30"
else
	res=`expr $1 / $2`
	echo "${res}"
fi

分别传入以下参数:

[root@localhost shell]# sh if_s.sh 35 10
3
[root@localhost shell]# sh if_s.sh 5 10
5 < 10
[root@localhost shell]# sh if_s.sh 15 10
15 between 10 and 20
[root@localhost shell]# sh if_s.sh 25 10
25 between 20 and 30

2.5 case…esac

其实就是其他语言中的switch流程,语法如下:

case ${variable} in 
	"val1")
		do sth
		;;
	"val2")
		do sth
		;;
	*)
		do sth
		;;
esac

例子:

#!/bin/bash

case $1 in
	1)
	echo "a"
	;;
	2)
	echo "b"
	;;
	3)
	echo "c"
	;;
	*)
	echo "other"
	;;
esac

执行:

[root@localhost shell]# sh case.sh 1
a
[root@localhost shell]# sh case.sh 2
b
[root@localhost shell]# sh case.sh 3
c
[root@localhost shell]# sh case.sh 4
other

修改下,对输入的参数进行case:

#!/bin/bash

read -p "input num:" num
case $num in
	1)
	echo "a"
	;;
	2)
	echo "b"
	;;
	3)
	echo "c"
	;;
	*)
	echo "other"
	;;
esac
[root@localhost shell]# sh case.sh
input num:1
a
[root@localhost shell]# sh case.sh
input num:2
b
[root@localhost shell]# sh case.sh
input num:3
c
[root@localhost shell]# sh case.sh
input num:65
other

三、 函数

#!/bin/bash

function test(){
	echo "$1"
	echo "$2"
	echo "$3"
	echo "$@"
	echo "total param:$#"
	echo "$0"
}
test 1 2 3 4

执行:

1
2
3
1 2 3 4
total param:4
fun.sh

函数的语法和其他语言基本一致,不过小括号内没有参数项,获取参数和前面获取脚本传入的参数方法一样,也是通过** N ∗ ∗ 获 取 指 定 参 数 , ∗ ∗ N**获取指定参数,** N@**为所以参数

函数的调用:

function_name param1 param2 ... paramn

四、循环

4.1 while

#!/bin/bash

i=5
while [ "${i}" -gt 0 ]
do
	echo $i
	i=`expr $i - 1`
done
echo "until do..."
until [ "$i" -gt 5 ]
do
	echo $i
	let "i++"
done

以上脚本,先让i从5打印到1,每次减1,然后再让i从0打印到5,每次自加1

注:let命令参考最后

while的语法如下:

while [ 条件 ]
do
   ...
done
# 或者
until [ condition ]
do
	...
done

4.2 for

for循环语法如下:

for var in item1,item2...itemN
do	
	....
donefor (( 初始值; 限制; 运算))
do
	..
done

和其他语言基本一致。

for (( i=0; i<=5; i=i+1 ))
do
        echo ${i}
done
echo "---------"
filelist=$(ls ./)
for file in ${filelist}
do
        echo $file
done
echo '----------'
for i in "$(seq 1 10)"
do
        echo ${i}
done

打印0到5,然后列出当前目录文件,再打印0到10:

[root@localhost shell]# sh fors.sh
0
#!/bin/bash
1
2
3
4
5
---------
=
0
add.sh
case.sh
dir1
file1
file2
fors.sh
fun.sh
hello.sh
if_s.sh
test_script.sh
variable2.sh
variable.sh
while_s.sh
----------
1 2 3 4 5 6 7 8 9 10
  • seq

    和python的range差不多,生成指定范围的序列

let

let命令可以执行多条表达式,用于计算的工具,在let中不需要使用$符号,支持其他语言中的++--+=-=等操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值