本文简单记录了Shell脚本的相关知识。预计阅读时间10分钟+。
变量名=变量值
A=hello # 定义变量A,其值是hello
echo $A # 调用变量,注意要给钱的,“$”
注意:
调用其他的形式:
1. ${}
取消变量:unset A
变量名=变量值
A=1546
echo $A
输出:
1546
``(反撇号)或$()
A=`hostname`
echo $A
输出:
algo-System-Product-Name
B=`data +%F`
echo ${B}
输出:
2021-12-27
read [选项] 变量名
选项 | 功能 |
---|---|
-p | 定义提示用户的信息 |
-n | 定义字符数(限制输入长度) |
-s | 不显示(用户输入的内容) |
-t | 定义超时时间 |
用法1:用户自己定义变量值
read name
harry
echo $name
harry
read -p "Input your name:" name
Input your name:tom
echo $name
tom
用法2:变量值来自文件
cat 1.txt
10.1.1.1 255.255.255.0
read ip mask < 1.txt
echo $ip
10.1.1.1
echo $mask
255.255.255.0
declare [选项] 变量名=变量值
选项 | 功能 |
---|---|
-i | 将变量看成整数 |
-r | 定义只读变量 |
-a | 定义普通数组,查看普通数组 |
-A | 定义关联数组;查看关联数组 |
-x | 将变量通过环境导出 |
- 当前用户自定义的变量,==当前进程有效,其他进程或子进程无效==
- 当前进程有效,子进程也可以用
- env:查看当前用户环境变量
- 所有用户生效,/env/bashrc
- shell本身已经固定好了它的名字和作用
内置变量 | 含义 |
---|---|
$? | 上一条命令执行后返回的状态;状态值为0表示执行正常,非0表示执行异常或错误 |
$0 | 当前执行的程序或脚本名 |
$# | 脚本后面接的参数的个数 |
$* | 脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开 |
$@ | 脚本后面所有参数,参数是独立的,也是全部输出 |
$1-$9 | 脚本后面的位置参数,$1表示第1个位置参数,依次类推 |
${10}-${n} | 扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上扩起来) |
$$ | 当前所在进程的进程号,如echo $$ |
$! | 后台运行的最后一个进程号(当前终端) |
!$ | 调用最后一条命令历史中的参数 |
expr 记得加空格如:expr 10 - 5,乘号需要转义 【实际操作貌似不用了,我的没有转义也可以使用】
表达式 | 举例 |
---|---|
$(()) | echo $((1+1)) 输出2 |
$[] | echo $[10-5] 输出5 |
expr | expr 10 / 5 注意空格 |
let | n=1;let n+=1 等价于 let n=n+1 |
- 对于变量没什么影响
- 格式1:test 条件表达式
- 格式2: [ 条件表达式 ]
- 格式3:[[ 条件表达式 ]] ,支持正则 =~
注意:
- 格式2和格式3,[空格+表达式+空格],两边都有空格哦
判断参数 | 含义 |
---|---|
-e | 判断文件是否存在(任何类型文件) |
-f | 判断文件是否存在并是一个普通文件 |
-d | 判断文件是否存在并且是一个目录 |
-L | 判断文件是否存在并且是一个软连接文件 |
-b | 判断文件是否存在并且是一个块设备文件 |
-S | 判断文件是否存在并且是一个套接字文件 |
-c | 判断文件是否存在并且是一个字符设备文件 |
-p | 判断文件是否存在并且是一个命名管道软件 |
-s | 判断文件是否存在并且是一个非空文件(有内容) |
判断参数 | 含义 |
---|---|
-r | 当前用户对其是否可读 |
-w | 当前用户对其是否可写 |
-x | 当前用户对其是否可执行 |
-u | 是否有suid,高级权限冒险位 |
-g | 是否sgid,高级权限强制位 |
-k | 是否有t位,高级权限粘滞位 |
判断参数 | 含义 |
---|---|
file1 -nt file2 | 比较file1是否比file2新 |
file1 -ot file2 | 比较file1是否比file2旧 |
file1 -ef file2 | 比较是否为同一个文件,或者用于判断硬链接,是否指向同一个inode |
参数 | 含义 |
---|---|
-eq | 相等 |
-ne | 不等 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于等于 |
-le | 小于等于 |
判断参数 | 含义 |
---|---|
-z | 判断是否为空字符串,字符串长度为0成立 |
-n | 判断是否为非空字符串,字符串长度不为0成立 |
string1 = string2 | 判断字符串是否相等 |
string1 != string2 | 判断字符串是否不相等 |
逻辑运算符,从左往右看
符号 | 含义 |
---|---|
-a 和 && | 逻辑与 |
-o 和 | | | 逻辑或 |
特别说明:
- && 前面的表达式==为真==,才会执行后面的代码
- | | 前面的表达式==为假==,才会执行后面的代码
- ; ==只==用于==分割==命令或表达式
if [ condition ];then
command
command
fi
或
[ 条件 ] && command
分岔路口,二选一
if [ condition ];then
command
else
command
fi
或
[ 条件 ] && command1 || command2
选择很多,能走的只有一条
if [ condition1 ];then
command1
elif[ condition2 ];then
command2
else
command3
fi
if [ condition1 ];then
command1
if [ condition2 ];then
command2
else
if [ condition3 ];then
command3
elif [ condition4 ];then
command4
else
command5
fi
使用场合:循环次数已知
for variable in {list}
do
command
command
...
done
或者
for variable in a b c
do
command
...
done
- 循环次数用户指定
for variable
do
command
command
...
done
for ((expr1;expr2;expr3))
do
command
command
...
done
expr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出
for(( i=1;i<=5;i++))
do
echo $i
done
# 普通方式
定义变量; while[ 表达式 ];do 程序;let i++;done
# 类C风格
定义变量;while((表达式));do 程序;let i++;done
条件假进入循环,真退出循环
until expression [ 1 -ed -1] (( 1 >= 1))
do
command
...
done
Regular Expression、regex或regeexp,缩写为RE)
元字符:如:点.
、星*
、问号?
等。
前导字符:位于元字符前的字符
符号 | 解释 | 案例 |
---|---|---|
. | 匹配除了换行符 以外的任意单个字符 |
|
* | 前导字符出现0次或连续多次 | |
.* | 任意长度字符 | ab.* |
^ | 行首(以…开头) | ^root |
$ | 行尾(以…结尾) | bash$ |
^$ | 空行 | |
[] | 匹配括号里任意单个字符或一组单个字符 | [abc] |
[^] | 匹配不包含括号里任意单个或一组单个字符 | [^abc] |
^[] | 匹配以括号里任意单个字符或一组单个字符开头 | ^[abc] |
^[ ^ ] | 匹配不以括号里任意单个字符或一组单个字符开头 | ^[ ^abc ] |
符号 | 解释 | 案例 |
---|---|---|
< | 取单词的头 | |
> | 取单词的尾 | |
< > | 精确匹配 | |
{n} | 匹配前导字符连续出现n次 | |
{n, } | 匹配前导字符至少出现n次 | |
{n, m} | 匹配前导字符出现n次与m次之间 | |
( ) | 保存被匹配的字符 | |
\d | 匹配数字(grep -P) | [0-9] |
\w | 匹配字符数字下划线(grep -P) | [a-zA-Z0-9_] |
\s | 匹配空格、制表符、换页符(grep -P) | [\t\r\n] |
-E
,或者用egrep
-r
符号 | 解释 | 案例 |
---|---|---|
+ | 匹配一个或多个前导字符 | |
? | 匹配零个或一个前导字符 | |
| | 或 | |
() | 组字符(看成整体) | |
{n} | 前导字符重复n次 | |
{n,} | 前导字符重复至少n次 | |
{n,m} | 前导字符重复n到m次 |
表达式 | 功能 |
---|---|
[:alnum:] | 字母与数字字符 |
[:alpha:] | 字母字符(包括大小写) |
[:blank:] | 空格与制表符 |
[:digit:] | 数字 |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:punct:] | 标点符号 |
[:space:] | 包含换行符,回车等在内的所有空白 |
一行一行
读取文件内容并按照要求
进行处理
,把处理后的结果输出到屏幕
不会直接修改源文件
sed [选项] ‘处理动作’ 文件名
常见选项
选项 | 含义 |
---|---|
-e | 进行多项(多次)编辑 |
-n | 取消默认输出 |
-r | 使用扩展正则表达式 |
-i | 原地编辑(修改文件) |
-f | 指定sed脚本文件名 |
常见动作
注意:所有动作
都在单引号里。
动作 | 含义 |
---|---|
‘p’ | 打印 |
‘i’ | 在指定行之前插入内容 |
‘a’ | 在指定行之后插入内容 |
‘c’ | 替换指定行所有内容 |
‘d’ | 删除指定行 |
对文件进行搜索替换
- sed [选项] `'s/搜索内容/替换内容/动作'` 需要处理的文件
- p打印;全局替换g
命令 | 解释 |
---|---|
r | 从另外文件中读取内容 |
w | 内容另存为 |
& | 保存查找串以便在替换串中引用 |
= | 打印行号 |
! | 对所选行以外的所有行应用命令,放到行数之后 |
q | 退出 |
#!/bin/sed -f
注意事项:
脚本文件只一个sed命令行清单。'commands'
在每行的末尾不能有任何空格、制表符(tab)或其他文本。
如果在一行中有多个命令,应用分号分割。
不需要且不可用引号保护命令
#号开头的行为注释
语法结构:
awk 选项 '命令部分' 文件名
特别说明:
引用shell变量需要用==双引号引起==
常用选项介绍
命令 | 功能 |
---|---|
-F | 定义字符按分割符号,默认的分隔符是空格 |
-v | 定义变量并赋值 |
‘命名部分说明’
正则表达式,地址定位
'/root/{awk语句}' sed中:'/root/p'
{awk语句1;awk语句2;…}
'{print $0; print $1}' sed中:'p'
BEGIN…END…
'BEGIN{awk语句};{处理中};END{awk语句}' 'BEGIN{awk语句};{处理中}' '{处理中};END{awk语句}'
脚本编写
#!/bin/awk -f # 定义魔法字符
以下是awk引号里的命令清单,不要用引号保护命令,多个命令用分号间隔
BEGIN{FS=":"}
NR==1,NR==3{print $1"\t"$NF}
脚本执行
方法1:
awk 选项 -f awk的脚本文件 要处理的文本文件
awk -f awk.sh filename
方法2:
./awk的脚本文件(或绝对路径) 要处理的文本文件
./awk.sh filename
变量 | 变量说明 | 备注 |
---|---|---|
$0 | 当前处理行的所有记录 | |
$1,$2,$3…$n | 文件中每行以间符号分割的不同字段 | awk -F: ‘{print $1,$3}’ 1.txt |
NF | 当前记录的字段数(列数) | awk -F: ‘{print NF}’ 1.txt |
$NF | 最后一列 | $(NF-1)表示倒数第二行 |
FNR/NR | 行号 | |
FS | 定义间隔符 | ‘BEGIN{FS=":"};{print $1,$3}’ |
OFS | 定义输出字段分隔符,默认空格 | |
RS | 输入记录分隔符,默认换行 | |
ORS | 输出记录分隔符,默认换行 | |
FILENAME | 当前输入的文件名 |
awk -F: '{print $1,$3}' /etc/passwd
awk使用一行作为输入,并经这一行赋给内部变量$0,每一行可称为一个记录,以换行符(RS)结束;
每行被间隔符:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始;
问:awk如何知道用空格来分割字段呢?
答:因为有一个内部变量FS来确定字符段分隔符。初始时,FS赋为空格
awk使用print函数打印字段,打印出来的字段会以空格分隔,因为1,3之间有一个逗号。都好比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格;
awk处理完一行后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分割成字段并进行处理。该过程将持续到所有行处理完毕。
print函数 类似echo
# data | awk '{print "Month: "$2"\nYear: "$NF}'
# awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd
printf 函数 类似echo -n
# awk -F: '{print "%-15s %-10s %-15s\n", $1, $2, $3}' /etc/passwd
# awk -F: '{print "|%15s| %10s| %15s|\n", $1, $2, $3}' /etc/passwd
# awk -F: '{print "|%-15s| %-10s| %-15s|\n", $1, $2, $3}' /etc/passwd
%s 字符类型
%d 数值类型
- 表示左对齐,默认是右对齐
printf默认不会再行尾自动换行,加 \n
# awk -v NUM=3 -F: '{print $NUM}' /etc/passwd 【注意】
# awk -v NUM=3 -F: '{print NUM}' /etc/passwd
# awk -v num=1 'BEGIN{print num}'
1
# awk -v num=1 'BEGIN{print $num}' 【注意】
注意:
awk中调用定义的变量不需要加$
'BEGIN{开始处理之前};{处理中};END{处理结束后}'
格式:
awk 选项 '正则,地址定位{awk语句}' 文件名
{if(表达式){语句1;语句2;...}}
案例:
# awk -F: '{if($3>=500 && $3<=60000) {print $1,$3}}' passwd
# awk 'BEGIN{if($(id -u)==0){print "admin"}}'
admin
格式:
{if(表达式){语句;语句;...}} else {语句;语句;...}}
awk -F: '{if($3>=500 && $3<=60000) {print $1"是普通用户"} else {print $1"不是普通用户"}}' passwd
awk 'BEGIN{if($(id -u)>=500 && $(id -u) !=65534) {print "是普通用户"} else {print "不是普通用户"}}'
格式:
{if(表达式1) {语句;语句;...} elif(表达式2) {语句;语句;...} elif(表示3) {语句;语句;...} else {语句;语句;...}}
awk -F: '{if($3==0) {print $1"是普通用户"} elif($3>=1 && $3<=499) {print $1"不是普通用户"}}' passwd
1、 Linux export命令用于设置或显示环境变量。
2、在shell中执行程序时,shell会提供一组环境变量。export可新增,修改或删除环境变量,供后续执行的程序使用。export的效力仅及于该次登陆操作。
选项 | 解释 |
---|---|
-f | 代表 [变量名称] 中为函数名称 |
-n | 删除指定的变量,注:变量实际未删除,知识不会输出到后续指令的执行环境中。 |
-p | 列出所有的shell赋予程序的环境变量 |