zl程序教程

您现在的位置是:首页 >  其他

当前栏目

shell 脚本基础入门小抄

2023-09-14 09:15:28 时间

学习笔记来源:骏马金龙大佬的博客空间

Shell:Shell系列文章 | 骏马金龙 (junmajinlong.com)

bash 注释

使用#开头的行被当作注释,除了#!,只支持单行注释

[root@vm-01 scripts]# cat basics.sh
#!/bin/bash
#by whale
#20220915


echo "helloworld" # This is a note
#echo "helloworld" # This is a note
[root@vm-01 scripts]#

bash 基本数据类型

bash 中基本数据类型只有字符串类型

[root@vm-01 scripts]# echo helloworld
helloworld
[root@vm-01 scripts]# echo 123
123
[root@vm-01 scripts]#

可以使用declare -i强制声明为数值类型

bash 中字符串串联

直接将2段字符串连一起就行

[root@vm-01 scripts]# echo hello world
hello world
[root@vm-01 scripts]# echo 123 456
123 456
[root@vm-01 scripts]#

变量的赋值和引用

[root@vm-01 scripts]# name="whale"					# 变量名=值
[root@vm-01 scripts]# echo $name					# 直接$变量名引用
whale
[root@vm-01 scripts]# echo ${name}					# 也可以通过${变量名}
whale
[root@vm-01 scripts]# echo $name1					# 可以直接引用不存在的变量名,返回是NULL

[root@vm-01 scripts]# name=							# 可以定义NULL变量
[root@vm-01 scripts]# echo $name

[root@vm-01 scripts]#

变量替换

命令执行开始前,shell 会将变量的赋值替换到引用变量的位置处

[root@vm-01 scripts]# name=whale
[root@vm-01 scripts]# echo "My name is $name"		# 命令执行前,会替换变量name的值
My name is whale
[root@vm-01 scripts]#

命令替换

替换方式:$()或者反引号``

[root@vm-01 scripts]# echo "time is $(date)"		# $()使用命令替换
time is 2022年 09月 15日 星期四 20:42:39 CST
[root@vm-01 scripts]# echo "time is `date`"			# ``反引号进行命令替换
time is 2022年 09月 15日 星期四 20:42:54 CST
[root@vm-01 scripts]#

算术运算

[root@vm-01 scripts]# num=87						# 使用 let ,变量名不用加 $,是作为单独的命令存在
[root@vm-01 scripts]# let num_1=num+2				
[root@vm-01 scripts]# echo $num_1
89
[root@vm-01 scripts]# echo "1+1=$(let 1+1)"				# 不能写在其他命令行里面
1+1=
[root@vm-01 scripts]# num=33
[root@vm-01 scripts]# echo $[num+33]					# 可以写在内部
66
[root@vm-01 scripts]# echo $((num+33))
66

变量替换优于算术替换,所以可以使用变量名或引用变量的方式

[root@vm-01 scripts]# a=10
[root@vm-01 scripts]# b=$(($a+10))
[root@vm-01 scripts]# echo $b
20
[root@vm-01 scripts]# echo $(($b+$a))
30
[root@vm-01 scripts]# echo $[$a+$b]
30
[root@vm-01 scripts]#

退出状态码

每一个命令执行完以后,都会有一个进程退出状态码,进程退出状态码用来表示该进程是否正常退出

$?:特殊变量,判断最后一个命令是否正常退出

  • 值为0:进程成功执行,正常退出
  • 值不为0:进程未成功执行,非正常退出

所有的条件判断,循环语句,都以0退出状态码表示 true,非0表示 false

[root@vm-01 scripts]# date
2022年 09月 15日 星期四 20:56:00 CST
[root@vm-01 scripts]# echo $?
0													# 0,最后一条命令执行成功
[root@vm-01 scripts]# datdasd
-bash: datdasd: 未找到命令
[root@vm-01 scripts]# echo $?
127													# 非0 最后一条命令执行有错误
[root@vm-01 scripts]#

exit 命令

退出当前shell 进程,并指定退出状态码,默认退出状态码为0

exit 170

后台执行命令 &

命令后面加一个&就可以将它放在后台去执行

[root@vm-01 ~]# sleep 1 &
[1] 1749
[root@vm-01 ~]# date
2022年 09月 15日 星期四 21:10:46 CST
[1]+  完成                  sleep 1
[root@vm-01 ~]#

多命令组合

顺序执行

[root@vm-01 ~]# echo 1;echo 2;echo 3				# 多个命令用;组合,按顺序执行
1
2
3
[root@vm-01 ~]#

按状态码

[root@vm-01 ~]# echo 1 && echo 2			#  && 前一个命令退出状态码为0时,才执行下一个命令
1
2
[root@vm-01 ~]# echo1 && echo 2				# # 前一个命令退出状态码不为0时,不会去执行下一个命令
-bash: echo1: 未找到命令
[root@vm-01 ~]# echo 1 || echo 2			# || 前一个命令退出状态码不为0时,才去执行下一个命令
1
[root@vm-01 ~]# echo1 || echo 2
-bash: echo1: 未找到命令
2
[root@vm-01 ~]#

状态码结合(逻辑结合)

echo 1 && echo 2 && echo 3	## 各命令正确执行后执行下一个
echo 1 && echo 2 || echo 3	## 前2个命令都正确执行则不会去执行第三个命令,只要有一个异常,则回去执行第三个命令
echo 1 || echo 2 && echo 3  ## 第一个命令正确执行就会执行第三个命令;第一个命令不正确,第二个要正确执行,才会去执行第三个

小括号命令组合

在子 shell 中执行的

[root@vm-01 ~]# (sleep 10;sleep 20;sleep 30)



## 查找子 shell 进程
[root@vm-01 ~]# ps -ef | grep sleep
root       1766   1764  0 21:25 pts/0    00:00:00 sleep 20
root       1802   1771  0 21:25 pts/1    00:00:00 grep --color=auto sleep
[root@vm-01 ~]#

大括号命令组合

当前 shell 中执行的

[root@vm-01 scripts]# { echo 1;echo 2;echo 3; }		## 使用 { 命令1;命令2;命令3; }
1
2
3
[root@vm-01 scripts]# {							## 使用 {} 进行分行书写
> echo 1
> echo 2
> echo 3
> }
1
2
3
[root@vm-01 scripts]#

基本重定向

改变文件描述符目标的行为被成为重定向:重新确定数据的流向

  • fd=0:标准输入,表示程序默认从哪里读取数据

  • fd=1:标准输出,表示程序默认将数据输出到哪里

  • fd=2:标准错误,表示程序默认将错误信息输出到哪里

  • fd=0的标准输入是/dev/stdin文件

  • fd=1的标准输出是/dev/stdout文件

  • fd=2的标准错误是/dev/stderr文件

shell 中的几种基础重定向:> 输出 < 输入

  • [n]>file:覆盖式输出重定向,输出到fd=n的数据改变流向输出到file文件中,file不存在则创建,file存在则先清空再写入数据

    • 省略n时>file,等价于1>file,即标准输出覆盖重定向到file文件中
  • [n]>>file:追加式输出重定向,输出到fd=n的数据改变流向输出到file文件的尾部,file不存在则创建,file存在则直接追加在文件尾部

    • 省略n时>>file,等价于1>>file,即标准输出追加重定向到file文件中
  • [n]<file:输入重定向,以读取模式打开file文件并分配fd=n,file不存在则报错

    • 省略n时<file,等价于0<file,即直接从file中读数据
    • 通常程序都只从fd=0中读数据,所以当n不等于0时,需要多做一步操作3<file <&3
  • &>file:这是特殊的重定向方式,表示将标准错误和标准输出都重定向到file文件中,等价于>file 2>&1

  • &>>file:这是特殊的重定向方式,表示将标准错误和标准输出都追加到file文件中,等价于>>file 2>&1

[root@vm-01 scripts]# cat basics.sh
helloworld
[root@vm-01 scripts]# echo "1" > basics.sh
[root@vm-01 scripts]# cat basics.sh
1
[root@vm-01 scripts]# echo "2" 1> basics.sh
[root@vm-01 scripts]# cat basics.sh
2
[root@vm-01 scripts]# echo "3" >> basics.sh
[root@vm-01 scripts]# cat basics.sh
2
3
## grep 'bin' <<<"hello $PATH"

管道

[root@vm-01 scripts]# echo 1 | cat | grep 1
1
[root@vm-01 scripts]#

一个竖线就代表一个管道:第一个命令的标准输出会放进管道,第二个命令会从管道中读取处理,以此类推,可以产生任意数量的管道

tee

将一份标准输入原样拷贝到标准输出和0或多个文件中。换句话说,tee的作用是数据多重定向

[root@vm-01 scripts]# tee --help
用法:tee [选项]... [文件]...
将标准输入复制到每个指定文件,并显示到标准输出。

  -a, --append          内容追加到给定的文件而非覆盖
  -i, --ignore-interrupts       忽略中断信号
      --help            显示此帮助信息并退出
      --version         显示版本信息并退出
[root@vm-01 scripts]# echo "helloworld"| tee file1 file2 file3
helloworld
[root@vm-01 scripts]# cat file1
helloworld
[root@vm-01 scripts]# cat file2
helloworld
[root@vm-01 scripts]# cat file3
helloworld
[root@vm-01 scripts]#

进程替换

bash 支持进程替换,并不是所有的shell都支持进程替换

进程替换则是把一个进程的输出回馈给另一个进程 (换句话说,它把一个命令的结果发送给另一个命令)

进程替换先让命令(命令合集)放入后台异步执行,并且不会等待命令执行完;

<(命令合集)		## 每一个进程替换都是一个虚拟文件,文件内容产生者
>(命令合集)		## 被命令所读取的
[root@vm-01 scripts]# cat <(ls -l)					## 数据的产生者
总用量 4
-rw-r--r-- 1 root root 22 915 22:14 basics.sh
[root@vm-01 scripts]# echo whale|read name
[root@vm-01 scripts]# echo $name

[root@vm-01 scripts]# read name < <(echo whale)
[root@vm-01 scripts]# echo $name
whale
[root@vm-01 scripts]# echo whale > >(read name;echo $name)
whale

条件测试语句

  • test

  • [ ]

  • [[]]

文件类测试

  • -e file 文件是否存在(exist)
  • -f file 文件是否存在且为普通文件(file)
  • -d file 文件是否存在且为目录(directory)
  • -b file 文件是否存在且为块设备block device
  • -c file 文件是否存在且为字符设备character device
  • -S file 文件是否存在且为套接字文件Socket
  • -p file 文件是否存在且为命名管道文件FIFO(pipe)
  • -L file 文件是否存在且是一个链接文件(Link)
[root@vm-01 scripts]# test -e basics.sh
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# test -e basics.shx
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# [ -e basics.sh ]
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# [ -e basics.shx ]
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# [[-e basics.sh]]
-bash: [[-e: 未找到命令
[root@vm-01 scripts]# [[ -e basics.sh ]]
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# [[ -e basics.shx ]]
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]#

文件属性类测试

  • -r file 文件是否存在且当前用户可读
  • -w file 文件是否存在且当前用户可写
  • -x file 文件是否存在且当前用户可执行
  • -s file 文件是否存在且大小大于0字节,即检测文件是否非空文件
  • -N file 文件是否存在,且自上次read后是否被modify
[root@vm-01 scripts]# ll
总用量 4
-rw-r--r-- 1 root root 22 915 22:14 basics.sh
[root@vm-01 scripts]# test -x basics.sh
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# test -r basics.sh
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# [ -r basics.sh ]
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]#

文件之间的比较

  • file1 -nt file2 (newer than)判断file1是否比file2新
  • file1 -ot file2 (older than)判断file1是否比file2旧
  • file1 -ef file2 (equal file)判断file1与file2是否为同一文件
[root@vm-01 scripts]# ll
总用量 8
-rw-r--r-- 1 root root 22 915 22:14 basics.sh
-rw-r--r-- 1 root root 22 916 00:06 basics.sh.bak
[root@vm-01 scripts]# test basics.sh -nt basics.sh.bak
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# test basics.sh -ot basics.sh.bak
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# ln basics.sh basics
[root@vm-01 scripts]# ls
basics  basics.sh
[root@vm-01 scripts]# test basics -ef basics.sh
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]#

数值大小比较

  • int1 -eq int2 两数值相等(equal)
  • int1 -ne int2 两数值不等(not equal)
  • int1 -gt int2 n1大于n2(greater than)
  • int1 -lt int2 n1小于n2(less than)
  • int1 -ge int2 n1大于等于n2(greater than or equal)
  • int1 -le int2 n1小于等于n2(less than or equal)
[root@vm-01 scripts]# test 1 -eq 2
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# test 1 -eq 1
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# a=1
[root@vm-01 scripts]# b=2
[root@vm-01 scripts]# test $a -eq $b
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# test $a -ne $b
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# test $a -lt $b
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# [ $a -lt $b ]
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]#

字符串比较

  • -z str (zero)判定字符串是否为空?str为空串,则true
  • str1 = str2 str1和str2是否相同,相同则返回true。”==”和”=”等价
  • str1 == str2 str1和str2是否相同,相同则返回true。”==”和”=”等价
  • str1 != str2 str1是否不等于str2,若不等,则返回true
[root@vm-01 scripts]# name=
[root@vm-01 scripts]# test -z $name
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# name1=1
[root@vm-01 scripts]# name2=2
[root@vm-01 scripts]# test $name1 = $name2
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# test $name1 == $name2
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]# test $name1 != $name2
[root@vm-01 scripts]# echo $?
0

逻辑运算符

  • -a或&& (and)两表达式同时为true时才为true。
  • “-a”只能在test[]中使用,&&只能在[[]]中使用
  • -o或|| (or)两表达式任何一个true则为true。
  • “-o”只能在test或[]中使用,||只能在[[]]中使用
  • ! 对表达式取反
  • ( ) 改变表达式的优先级,为了防止被shell解析,应加上反斜线转义( )
[root@vm-01 scripts]# [ 1 -eq 1 ]
[root@vm-01 scripts]# echo $?
0
[root@vm-01 scripts]# [ ! 1 -eq 1 ]
[root@vm-01 scripts]# echo $?
1
[root@vm-01 scripts]#

if 语句

if 表达式1;then
    执行的动作1;
[elif 表达式2;then
    执行的动作2;]
...
[else (以上都不成立)执行的动作;]
fi
[root@vm-01 scripts]# cat basics.sh
#!/bin/bash
#Date 20220916
#Author whale
#this is if test scripts

if [ 1 -eq 2 ];then
    echo "1=2";
elif [ 1 -gt 2 ];then
    echo "1>2";
else echo "1<2";
fi
[root@vm-01 scripts]# if [ 1 -eq 2 ];then echo "1=2";elif [ 1 -gt 2 ];then echo "1>2";else echo "1<2";fi
1<2
[root@vm-01 scripts]#

case 语句

  • 除最后一个分支,每个分支都应该以;;结尾
  • 分支条件可以使用通配符
  • 最后的条件*代表了上述分支都不满足情况下的处理动作
## case 用于确定的分支判断
case 变量 in 
条件 1)
   执行动作1
 ;; 
 条件 2) 
   执行动作2
 ;; 
 条件 3) 
   执行动作3
 ;; 
 *) 
    无匹配后执行动作
 esac
[root@vm-01 scripts]# cat case.sh
#!/bin/bash
#Date 20220916
#Author whale
#this is a case example


case "$1" in
    1)
        echo "this is 1"
        ;;
    2)
        echo "this is 2"
        ;;
    3)
        echo "this is 3"
        ;;
    4|5)
        echo "this is 4 or 5"
        ;;
esac
[root@vm-01 scripts]# sh case.sh 1
this is 1
[root@vm-01 scripts]# sh case.sh 2
this is 2
[root@vm-01 scripts]# sh case.sh 4
this is 4 or 5
[root@vm-01 scripts]# sh case.sh 6
[root@vm-01 scripts]#

for 循环

## 第一种
for i in 值1 值2 值3 ...;do 动作集合 ;done

## 第二种:初始化语句,循环终点条件判断语句,每轮循环后执行的语句
for ((i=1; i<=j; i++));do 执行的命令;done
[root@vm-01 scripts]# cat for.sh
#!/bin/bash
#Date 20220916
#Author whale
#this is for example

for i in 1 2 3 4 ;do
    echo "${i}.helloworld";
done
[root@vm-01 scripts]# sh for.sh
1.helloworld
2.helloworld
3.helloworld
4.helloworld
[root@vm-01 scripts]# sh for-c.sh
1-helloworld
2-helloworld
3-helloworld
4-helloworld
[root@vm-01 scripts]# cat for-c.sh
#!/bin/bash
#Date 20220916
#Author whale
#this is for-c example

for ((i=1;i<=4;i++));do
    echo "${i}-helloworld";
done
[root@vm-01 scripts]#

while 循环

  • 表达式退出状态码为0 ,就循环一次,再测试,再循环,一直到表达式退出状态码不为0,则退出循环
while 表达式;do
    执行的动作;
done
[root@vm-01 scripts]# sh while.sh
1-helloworld
2-helloworld
3-helloworld
4-helloworld
[root@vm-01 scripts]# cat while.sh
#!/bin/bash
#Date 20220916
#Author whale
#this is while example

i=1
while [ $i -lt 5 ];do
    echo "${i}-helloworld"
    let i=i+1;
done
[root@vm-01 scripts]#
##########       while 与 read 命令的结合:读取文件,按每行读取##############
[root@vm-01 scripts]# cat test.log
192.168.204.1
192.168.204.2
192.168.204.3
192.168.204.4
192.168.204.5
[root@vm-01 scripts]# cat test.log | while read i;do echo "IP ADDR:$i";done
IP ADDR:192.168.204.1
IP ADDR:192.168.204.2
IP ADDR:192.168.204.3
IP ADDR:192.168.204.4
IP ADDR:192.168.204.5
[root@vm-01 scripts]#

shell 函数

函数内容:包含了实现这个功能相关的所有命令和逻辑

#############风格################
function 函数名 {函数体}
函数名() {函数体}
function 函数名() {函数体}

#############函数调用################
函数名
函数名 参数1 参数2 参数3
[root@vm-01 scripts]# sh function.sh
1-helloworld
2-helloworld
3-helloworld
[root@vm-01 scripts]# cat function.sh
#!/bin/bash
#Date 20220916
#Author whale
#this is function example

function test1() {
    echo "${1}-helloworld"
 }

test2() {
    echo "${2}-helloworld"
}

function test3 {
    echo "${3}-helloworld"
    return 200
    echo "${1}-helloworld"
}

test1 1 2 3
test2 1 2 3
test3 1 2 3
[root@vm-01 scripts]#