#! —— Shebang 符号: 说明使用哪种解释器执行shell命令
一、shell中的变量和符号
1.1 通配符
shell常见的通配符,注意与正则稍有不同:
字符 | 含义 | 实例 |
* | 匹配0个或多个任意字符 | a*b,a与b之间可以有任意长度的字符,也可以没有。 例如:aabcb,ab,azxcb... |
? | 匹配一个任意字符 | a?b,a与b之间必须但也只能存在一个字符,该字符可以是任意字符。 例如:aab,abb,acb... |
[list] | 匹配list中的任意单个字符 | a[xyz]b,a与b之间必须但也只能存在一个字符,该字符只能是x或y或z。 例如:axb,ayb,azb |
[!list] | 匹配除list中的任意单个字符 | a[!a-z]b,a与b之间必须但也只能存在一个字符,该字符不能是小写字母。 例如:aAb,a0b... |
[^] | 匹配除了中括号的一个字符。 | 例如[^0-9],匹配除了数字的字符,只会匹配集合中的一个 |
\ | 转义符。 让元字符回归本意 | 例如 echo \* |
1.2 变量
1.2.1 系统变量
$HOME(当前家目录) , $PWD(当前路径的绝对路径名), $SHELL(默认shell解析器), $USER(当前用户) 等。
1.2.2 自定义变量
1)例如:a=2, 等号左右两边不能有空格,unset a 清空变量值。变量定义规则:字母、数字、下划线,但是不能以数字开头。
2)变量默认类型都是字符串类型,不能直接进行运算,例如 c=1+1 ,输出值为1+1而非2。
3)变量值如果有空格,必须要用双引号或单引号引起来。如b="hello world"
4) 可将变量设置为全局变量,可供其他shell程序使用。格式 export 变量名。
1.2.2.1 变量赋值
1、显示赋值
变量名=变量值 // 注意:等号两边没有空格
例如:
ip=192.168.1.1
today=`date +%F` // 获取当前日志,通过 echo $today 查看变量值。 注意不是单引号,是反引号(~按键上的 符号)
$ echo $today
2022-11-05
today=$(date +%F) // 反引号 和 小括号 都可以括起来变量值
2、read 冲键盘读入变量值
read 变量名 // 执行后,手动输入的值就会保存到变量中
read -p “提示信息: ” 变量名
1.2.2.2 变量引用
“ ”(双引号):变量会被展开。
‘’(单引号):变量不会被展开。
例.
$ string="hello shell" // 定义一个变量
$ echo "-----test $string -----" // 双引号:展开引用
-----test hello shell -----
$ echo '-----test $string -----' // 单引号:不展开引用
-----test $string -----
1.2.2.3 命令替换——反引号或者$()
例. 创建一个带日志的文件
$ touch `date +%F`_debug.log
$ ll
-rw-r--r-- 1 z 197121 0 11月 5 14:53 2022-11-05_debug.log
或者
$ touch $(date +%F)_err.log
$ ll
-rw-r--r-- 1 z 197121 0 11月 5 14:53 2022-11-05_debug.log
1.2.3 特殊变量
变量 | 含义 |
$0 | 当前脚本的文件名。 |
$n(n≥1) | 传递给脚本或函数的第几个参数。例如,第一个参数是 $1,第二个参数是 $2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数。当被双引号 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前 Shell 进程 ID。对于 Shell 脚本,就是这些脚本所在的进程 ID。 |
例1. 给脚本文件传递参数
编写下面的代码,并保存为 test.sh:
#!/bin/bash
echo "Process ID: $$"
echo "File Name: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "All parameters 1: $@"
echo "All parameters 2: $*"
echo "Total: $#"
运行 test.sh,并附带参数:
[mozhiyan@localhost demo] ./test.sh Shell Linux
Process ID: 5943
File Name: bash
First Parameter : Shell
Second Parameter : Linux
All parameters 1: Shell Linux
All parameters 2: Shell Linux
Total: 2
例2给函数传递参数
编写下面的代码,并保存为 test.sh:
#!/bin/bash
#定义函数
function func(){
echo "Language: $1"
echo "URL: $2"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "All parameters 1: $@"
echo "All parameters 2: $*"
echo "Total: $#"
}
#调用函数
func Java http://c.biancheng.net/java/
运行结果为:
Language: Java
URL: http://c.biancheng.net/java/
First Parameter : Java
Second Parameter : http://c.biancheng.net/java/
All parameters 1: Java http://c.biancheng.net/java/
All parameters 2: Java http://c.biancheng.net/java/
Total: 2
1.2.4 解析器
查看系统中shell解析器的类型。 最常用的就是/bin/sh和/bin/bash。
1.2.5 在文件之间传递变量
$ cat public_var.sh // 自定义公共变量
#!/usr/bin/bash
export dir_path=$(PWD) // 通过export 声明为全局变量
export dir2_path=/home/
$ cat 1.sh
#!/usr/bin/bash
. public_var.sh // 通过. 或者source 方式在子shell中使用 自定义的全局变量
echo "----------------"
echo $dir_path
echo $dir2_path
1.2.6 变量的运算
1.2.6.1 整数运算
方法1: 使用expr。
加法:+、
减法:- 、
乘法: \* (乘法需要转义)、
除法:/ 、
取余: %
例:expr 1 + 2
方法2: 使用$(()) —— 注意是:双括号。
例: echo $((num1+num2))
方法3:使用$[]
例: sum=$[num1+num2]
方法4: 使用let (推荐)
例:let sum = num1+num2
1.2.6.2 小数运算 —— 计算器: bc 或者 awk、python
例:
$ echo "scale=2;6/2" | bc
awk 'BEGIN{print 1/2}'
1.2.7 变量内容删除、替换
1.3 重定向
1.3.1 参数解释
符号 | 说明 |
0 | 标准输入 |
1 | 标准输出 |
2 | 错误输出 |
/dev/null | Linux中的一个特殊文件,写入该文件的内容都将被丢弃 |
一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
- 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
- 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
- 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
默认情况下,是将 stdout(标准输出) 重定向到 file,command < file 将stdin 重定向到 file。
1.3.2 常用方法
符号 | 说明 |
> (重定向符) | 将标准输出重定向到文件 |
1> | 将标准输出重定向到文件,与>相同 |
2> | 将错误输出重定向到文件 |
2>&1 | 将错误输出重定向到标准输出 |
&> | 将标准输出和错误输出都重定向到文件, 2>&1 可以简写成:&> 或者 >& |
例1. 把 "一些内容" 写入到 filename.txt 文件中。
$echo "一些内容" > filename.txt
例2. 将标准输出 和 错误输出 都重定向到/dev/null。
$ command > /dev/null 2>&1
Tips:
1、>前是可以加数字来说明把什么内容重定向到文件中,默认是把标准输出重定向到文件中
2、 这里的 2> 之间不可以有空格,2> 是一体的时候才表示错误输出。
1.3.3 /dev/null 文件
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。
例. 屏蔽 stdout 和 stderr
$ command > /dev/null 2>&1
1.4 shell中的特殊符号
() : 在子shell中执行
(()) : 数值比较, 运算 C语言
$() : 命令替换, 等价于 一对反引号
$(()) :整数运算
{}:
${}:
[]:条件测试
[[]]: 条件测试,支持正则 =~
$[]:整数运算
二、条件测试
2.1 数值、字符串、文件测试
格式1: test 条件表达式
格式2: [ 条件表达式 ]
格式3: [[ 条件表达式 ]]
2.2 文件测试
[ 操作符 文件或者目录 ]
说明:
1、操作符
-e:是否存在
-d:是否是路径
-f:是否是文件
例:
[ -e dir | file ]
[ -d dir ]
[ -f file ] // 是否存在, 而且是文件
[ -r file ] // 当前用户对文件是否有读权限
2.3 数值比较
例.
[ 2 -gt 10 ] 大于
[ 2 -lt 10 ] 小于
[ 2 -eq 10 ] 等于
[ 2 -ne 10 ] 不等于
三、函数
3.1 定义
方法1:
函数名() {
功能实现;
}
方法2:
function 函数名 {
功能实现;
}
3.2 调用
函数名
函数名 参数1 参数2
说明:
传参 $1, $2
变量 local
返回值 return $?
例: 定义一个函数计算 阶乘
$ ./cal_factorial.sh 6 // 执行脚本: 传给脚本的参数 $1 = 6
---------------120---------------
$ cat cal_factorial.sh
#!/bin/bash
factorial() { // 函数定义
fac=1
for ((i=1;i<$1;i++))
do
fac=$[$fac * $i]
done
echo "---------------$fac---------------"
}
factorial $1 // 函数调用
四、shell 三剑客
三剑客的格式
grep ‘字符’ 文件
sed ‘命令’ 文件
awk ‘条件{命令}’ 文件
Tips:
单引号内就是正则表达式的用法。
4.1 grep —— 字符串搜索
grep [选项]… 查找条件 目标文件
说明:
- -i:查找时忽略大小写
- -v:反向查找,输出与查找条件不相符的行
- -f: 对比两个文件的相同行
- -c: 匹配的行数
- -R: 递归子目录
- -n: 显示匹配的具体行号
4.2 sed —— 按行编辑文本(增、删、改、选取、移动等)
读取文本,并根据指定的条件对文本内容进行编辑(增、删、改、移动等),最后输出所有行或者仅输出处理的某些行。
4.2.1 基本语法
sed[选项] '操作' 参数
sed [选项] -f scriptfile 参数
sed 的工作流程主要包括读取、执行和显示三个过程。
- 读取:sed 从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,pattern space)。
- 执行:默认情况下,所有的 sed 命令都在模式空间中顺序地执行,除非指定了行的地址,否则 sed 命令将会在所有的行上依次执行。
- 显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。
在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。
注意:
默认情况下所有的 sed 命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。
4.2.2 常用选项
- -e 或–expression=:表示用指定命令或者脚本来处理输入的文本文件。
- -f 或–file=:表示用指定的脚本文件来处理输入的文本文件。
- -h 或–help:显示帮助。
- -n、–quiet 或 silent:表示仅显示处理后的结果。
- -i:直接编辑文本文件。
4.2.3 常用操作
- a:增加,在当前行下面增加一行指定内容。
- c:替换,将选定行替换为指定内容。
- d:删除,删除选定的行。
- i:插入,在选定行上面插入一行指定内容。
- p:打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与“-n”选项一起使用。
- s:替换,替换指定字符。
- y:字符转换。
例1. 选择/打印 指定行
sed -n 'p' test.txt 输出所有内容 ,等同于使用cat
sed -n '3p' test.txt 输出第 3 行
sed -n '3,5p' test.txt 输出 3~5 行
sed -n '/[0-9]$/p' test.txt 输出以数字结尾的行
例2. 删除指定行
sed '2,4d' file_name 删除file_name 的2到4行
nl test.txt | sed '3d' 删除第 3 行。 nl 命令用于计算文件的行数
nl test.txt | sed '/cross/d' 删除包含cross 的行
nl test.txt | sed '/cross/!d' 删除不包含cross 的行
sed '/^[a-z]/d' test.txt 删除以小写字母开头的行
sed '/\.$/d' test.txt 删除以"."结尾的行
sed '/^$/d' test.txt 删除所有空行
例3. 替换符合条件的文本
// 在使用 sed 命令进行替换操作时需要用到 s(字符串替换)、c(整行/整块替换)、y(字符转换)命令选项
sed 's/l/L/2' test.txt 将每行中的第2 个l替换为L
sed 's/the/THE/g' test.txt 将文件中的所有the替换为THE
sed 's/o//g' test.txt 将文件中的所有o 删除(替换为空串)
sed 's/^/#/' test.txt 在每行行首插入#号
sed '/the/s/^/#/' test.txt 在包含the的每行行首插入#号
sed 's/$/EOF/' test.txt 在每行行尾插入字符串EOF
sed '3,5s/the/THE/g' test.txt 将第3~5行中的所有the替换为THE
sed '/the/s/o/O/g' test.txt 将包含the 的所有行中的o 都替换为 O
例4. 迁移符合条件的文本
// H,复制到剪贴板;g、G,将剪贴板中的数据覆盖/追加至指定行;w,保存为文件;r,读取指定文件;a,追加指定内容。
sed '/the/{H;d};$G' test.txt 将包含the的行迁移至文件末尾,{;}用于多个操作
sed '1,5{H;d};17G' test.txt 将第1~5行内容转移至第17行后
sed '/the/wout.file' test.txt 将包含the的行另存为文件out.file
sed '/the/r /etc/hostname' test.txt 将文件/etc/hostname的内容添加到包含the 的每行以后
sed '3aNew' test.txt 在第3行后插入一个新行,内容为New
sed '/the/aNew' test.txt 在包含the的每行后插入一个新行,内容为New
sed '3aNew1\nNew2' test.txt 在第3行后插入多行内容,中间的\n表示换行
4.2.4 使用脚本编辑文件
使用sed脚本,将多个编辑指令存放到文件中(每行一条编辑指令),通过“-f”选项来调用。
例. 将第 1~5 行内容转移至第 17 行后
sed '1,5{H;d};17G' test.txt
以上操作可以改用脚本文件方式:
sed -f opt.list test.txt
$ cat opt.list // 脚本中的指令
1,5H 将文件中的1--5行复制到剪切板
1,5d 删除文件中的1--5行
17G 将复制到剪切板中的1--5行追加到第17行之后
4.3 awk——以字段为单位进行处理(其实就是把一行数据分割,然后进行处理)
4.3.1 基本语法
awk '条件{命令1} 条件{命令2}...' file_name 1 file_name 2…
awk -f | -v 脚本文件 file_name 1 file_name 2…
说明:
1、sed命令常用于一整行的处理,而awk是将一行分为多个"字段"然后再进行处理,awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。
2、awk隐含循环,条件匹配多少次动作就会执行多少次,如果没有定义匹配条件默认是匹配所有数据行。
3、读到第一行时,匹配条件,然后执行指定动作,再接着读取第二行数据处理,不会默认输出
4、逐行读取输入文本,并根据指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互的情况下实现相当复杂的文本操作。
4.3.2 常用参数
1.$0 当前处理的行的整行内容, 代表一整行的数据
2.$n 当前处理行的第n个字段(即第n列)
3.NF 当前处理的行的字段个数, 即每一行拥有的字段总数
4.NR 当前处理的行的行号,即目前处理的是第几行的数据
5.FS 指定每行文本的字段分隔符,缺省为空格或制表位(tab)
6.RS 行分隔符,根据RS的定义把资料切割成许多条记录
7.FNR 读取文件的记录行号(从1开始,若读取新的文件依旧是从1开始)
8.OFS 输入字段的分割符(默认是空格)
9.ORS 输出行的分割符,默认为换行符
Tips:
1、像\n ,\t,这种符号应该用双引号括起来
2、NR,NF等变量要用大写,并且不需要 $
例1. 查找出/etc/passwd 的用户名、用户 ID、组 ID 等列
$ awk -F ’:’ ‘{print $1, $3, $4}’ /etc/passwd
工作原理
例2. 把file_name 文件中的前五行的第一列,第二列的数据列出来 (以[tab]或空格键分隔)
awk 'NR<6{print $1 $2}' file_name
例3. 打印匹配的行 Shell编程三剑客_LIUXU23的博客-CSDN博客_shell三剑客
例4. 打印符合条件的行
awk -F":" '{print $1"\t"$2}' passwd 用制表符作为分隔符输出
awk -F[:/] '{print $9}' passwd []中定义多个分隔符,只要看见其中一个都算作分隔符
awk '{print}' test.txt 输出所有内容
awk '{print $0}' test.txt 输出所有内容
awk 'NR==1,NR==3{print}' test.txt 输出第 1~3 行内容
awk '(NR>=1)&&(NR<=3){print}' test.txt 输出第 1~3 行内容
awk 'NR==1||NR==3{print}' test.txt 输出第 1 行、第 3 行内容
awk '(NR%2)==1{print}' test.txt 输出所有奇数行
awk '(NR%2)==0{print}' test.txt 输出所有偶数行
seq 200 | awk '$1%7==0 && $1~/7/' 打印1-200之间所有能被7整除的整数数字
awk '/^root/{print}' passwd 输出以root开头的行
awk '/nologin$/{print}' passwd 输出以 nologin 结尾的行
awk '{print$3}' test.txt 输出每行中(以空格或制表位分隔)的第3个字段
awk '{print$1,$3}' test.txt 输出每行中的第1、3个字段
// 网卡的IP、流量
ifconfig ens33 | awk '/netmask/{print "本机的ip地址是"$2}'
ifconfig ens33 | awk 'RX p/{print $5"字节"}'
// 根分区的可用量
df -h | awk 'NR==2{print $4}'
4.3.3 特殊用法
逐行执行开始之前执行什么任务,结束之后再执行什么任务,用BEGIN、END
- BEGIN一般用来做初始化操作,仅在读取数据记录之前执行一次
- END一般用来做汇总操作,仅在读取完数据记录之后执行一次
例1. awk 的运算
awk 'BEGIN{x=10;print x}' 如果不用引号awk就当作一个变量来输出了,所有不需要加$了
awk 'BEGIN{print x+1}' x不指定初始值、初始值就为0,如果是字符串则默认为空
awk 'BEGIN{print 1.2+3.4}' 支持小数运算
例2. 打印第1、2列
awk -F":" '{print $1" "$2}' passwd 空格需要用双引号引用起来,如果不引默认以变量看待,如果是常量就需要双引号引起来
例3. 在打印之前定义字段分隔符为冒号
awk 'BEGIN{FS=":"}{print $1}' passwd
例4. 输出低1、2列,并在第1、2列中间加分隔符--
awk 'BEGIN{FS=":";OFS="--"}{print $1,$2}' passwd
// OFS定义了输出时以什么为分隔,$1$2中间要同逗号分隔,因为逗号默认被映射为OFS变量,而这个变量默认是空格
例5. 把多行合并为一行输出
awk 'BEGIN{ORS=" "}{print $0}' passwd
把多行合并成一行输出,输出的时候自定义以空格分隔每行,本来默认是回车键
4.3.4 高级用法
例1. 调用函数getline,读取一行数据的时候并不是等到当前行而是当前行的下一行
seq 10 | awk '{getline;print $0}'
例2. if + awk
单分支为if ( ) { }
双分支为if ( ) { }else{ }
多分支为if ( ) { }else if ( ) { }else{ }
单分支 awk -F: '{if(条件判断){执行的指令操作}}‘ 处理对象(文件、管道、标准输入)
双分支 awk -F: '{if(条件判断){执行的指令操作}else{执行的操作指令}}‘ 处理对象(文件、管道、标准输入)
多分支 awk -F: '{if(条件判断){执行的指令操作}else if(条件表达式2){操作指令}else{其他的操作指令}}‘ 处理对象(文件、管道、标准输入)
例2. 打印符合条件的行
awk -F: '{if($3<10){print $0}}' /etc/passwd 第三列小于10的打印整行
awk -F: '{if($3<10){print $3}else{print $1}}' /etc/passwd 第三列小于10的打印第三列,否则打印第一列
例3. BEGIN-- END
awk 'BEGIN{x=0};/\/bin\/bash$/ {x++;print x,$0};END {print x}' /etc/passwd
// 统计以/bin/bash结尾的行数,等同于grep -c "/bin/bash$" /etc/passwd
BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中的动作;
awk再处理指定的文本;
再执行ENG模式中指定的动作,ENG{ }语句块中,往往会放入打印结果等语句
常用命令
公共命令
调试方式运行shell 脚本——bash -vx xxx.sh
$ bash -vx 1.sh
#!/usr/bin/bash
. public_var.sh
+ . public_var.sh
#!/usr/bin/bash
export dir_path=$(PWD)
+++ PWD
++ export dir_path=/d/eBook/Shell/test
++ dir_path=/d/eBook/Shell/test
export dir2_path=/home/
++ export dir2_path=/home/
++ dir2_path=/home/
echo "----------------"
+ echo ----------------
----------------
echo $dir_path
+ echo /d/eBook/Shell/test
/d/eBook/Shell/test
echo $dir2_path
+ echo /home/
/home/
查看帮助信息——man cmd
例: man test // 查看test的帮助信息
type -a 查看 符号类型;或者 which
例如:
查看环境变量
echo $PATH // 查看指定变量
set // 查看所有变量
env // 查看环境变量