学习笔记来源:骏马金龙大佬的博客空间
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 9月 15 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 9月 15 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 9月 15 22:14 basics.sh
-rw-r--r-- 1 root root 22 9月 16 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]#