文章目录
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 8月 28 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设备 |
-c | character device设备 |
-S | socket文件 |
-p | FIFO文件 |
-L | 链接文件 |
2.1.2 文件权限测试
选项 | 作用 |
---|---|
-r | 是否有可读权限 |
-w | …写权限 |
-x | 可执行权限 |
-u | SUID属性 |
-g | SGID属性 |
-k | Sticky bit属性 |
-s | 是否存在,且为非空文件 |
2.1.3 文件比较
test file1 -[nt、ot、ef] file2
-nt | newer than file1比file2新 |
---|---|
-ot | older 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 string | string是否为空 |
-n string | string是否非空 |
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 8月 28 18:18 dir1
-rw-r--r--. 1 root root 0 8月 28 17:50 file1
-rw-r--r--. 1 root root 0 8月 28 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
....
done
或
for (( 初始值; 限制; 运算))
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中不需要使用$符号,支持其他语言中的++
、--
、+=
、-=
等操作