先设置脚本格式,tab键自动缩进4格
vim ~/.vimrc
autocmd FileType sh set ai ts=4
变量
1.自定义变量
unset a 或 a= //把变量置为空
set //查看所有变量
2.环境变量:系统定义好的变量
USER UID HOME SHELL HOSTNAME PWD
PS1 一级提示符
PS2 二级提示符
PATH 存储了命令的路径
/etc/profile 永久变量配置文件(所有用户)
~/.bash_profile (仅对单个用户生效)
env //查看所有环境变量
3.位置变量与预定义变量
$1 第一个参数
$2 第二个参数
$3 第三个参数
$0 脚本的名称
$# 所有参数的个数
$* 所有参数
$$ 当前进程的进程号
$? 上一个程序的返回状态码,0是成功,非0是失败
变量的扩展应用
1.三种引号对变量赋值的影响
" "使用双引号可以界定一个完整字符串,允许扩展以$引用其他变量。
' '界定范围,屏蔽特殊符号,禁用扩展,即便$也视为普通字符。
` `或$() 将命令的执行结果赋值到变量值
2.使用read命令从键盘读取变量值
read基本用法:
read -p "提示语" i //结合-p选项给出友好提示,执行后从会等待并接受用户输入,并赋值给变量i
3.stty终端显示控制
将回显功能关闭(stty -echo),将回显功能恢复(stty echo)。
4.使用export发布全局变量
默认情况下,自定义的变量为局部变量,只在当前Shell环境中有效,而在子Shell环境中无法直接使用。
export 变量名 //发布全局变量,可在子环境中使用
Shell中的数值运算
整数运算工具
1.expr命令
模板:expr 整数(变量) 运算符号 整数(变量)
参与运算的整数值与运算操作符之间需要以空格分开,引用变量时必须加$符号。
+ #加法
- #减法
\* #乘法,操作符应添加\转义
/ #除法,仅保留整除结果
% #求模
2.$[]或$(())表达式
乘法操作*无需转义,运算符两侧可以无空格;引用变量可省略 $ 符号;计算结果替换表达式本身,可结合echo命令输出。
x=1000
echo $[x*77]
3.let命令
expr或$[]、$(())方式只进行运算,并不会改变变量的值;而let命令可以直接对变量值做运算再保存新的值。
let a++ #变量a加1
let a-- #变量a减1
let a+=10 #变量a加10
let a-=10 #变量a减10
let a*=2 #变量a乘以2
let a/=2 #变量a除以2
let a%=3 #变量a除以3取余数
小数运算工具
1.bc交互式运算
bc #先执行bc命令进入交互环境,然后再输入需要计算的表达式。
2.bc非交互式运算
echo "1.1+1" | bc
echo "scale=2;10/3" | bc #scale可以定义结果是小数点后多少位
条件测试
使用“test 表达式”或者[ 表达式 ]都可以,注意空格不要缺少。
条件测试操作本身不显示出任何信息。所以可以在测试后查看变量$?的值来做出判断。
1.字符串
== 判断两边是否相等
!= 判断两边是否不等
-z 判断变量是否为空
! -z或-n 判断变量是否非空
2.逻辑组合
&& 与 A&&B 当A成功时,会执行B(两个成功才算真)
|| 或 A||B 当A失败时,会执行B(有一个成功就算真)
3.整数值比较
-eq 是否相等
-ne 是否不相等
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
4.识别文件/目录的状态
-e 判断对象是否存在,不管是目录还是文件
-f 判断对象是否为文件,存在且是文件
-d 判断对象是否为目录,存在且是目录
-r 判断当前用户对文件是否有读权限,对root无效
-w 判断当前用户对文件是否有写权限,对root无效
-x 判断当前用户对文件是否有x权限
if选择结构
1.单分支
if 条件测试;then
指令
fi
2.双分支
if 条件测试;then
指令
else
指令
fi
3.多分支
if 条件测试;then
指令
elif 条件测试;then
指令
...
else
指令
fi
for循环结构
for 变量名 in 值1 值2 值3 ...(有几个值,指令就执行几次) #{1..100} 循环100次,但不支持变量;a=100,"seq $a" 如果循环次数是通过变量决定可以用seq指令
do
指令
done
for ((初值;条件;步长)) #C语言风格的for循环格式
do
指令
done
while循环结构
while 条件测试 #根据条件的结果决定是否要执行任务,条件测试成功的话就执行,如果失败立刻结束循环 #: 冒号可以表示条件为真,例while :
do
指令
done
循环控制
中断及退出
exit 结束循环及整个脚本
break 结束循环,继续循环之后的任务
continue 结束本次循环,进入下一次循环
case分支
case分支属于匹配执行的方式,它针对指定的变量预先设置一个可能的取值,判断该变量的实际取值是否与预设的某一个值相匹配,如果匹配上了,就执行相应的一组操作,如果没有任何值能够匹配,就执行预先设置的默认操作。
case 变量 in
模式1) #可以使用 | 分隔预设多个值
命令;;
模式2)
命令;;
*)
默认命令
esac
Shell函数
函数:将一些重复使用的命令,定义为公共的语句块。
return是跳出函数(直接结束函数)
格式1:
function 函数名 {
命令
}
格式2:
函数名(){
命令
}
函数的调用
直接使用“函数名”的形式调用,如果该函数能够处理位置参数,则可以使用“函数名 参数1 参数2 .. ..”的形式调用。注意:函数的定义语句必须出现在调用之前,否则无法执行。
字符串处理
字符串的截取
使用 ${}表达式
格式:${变量名:起始位置:长度}
一个随机密码的案例,首先实现1个字符的随机产生。
x=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
n=$[RANDOM%62] #得到0~61随机数存在变量n中
p=$[x:n:1] #通过截取,将1个随机字符赋值给变量p
字符串的替换
只替换第1个子串
格式:${变量名/old/new}
替换全部子串
格式:${变量名//old/new}
删除
格式:${变量名//旧/ }
字符串的匹配删除
例如有个变量a=abcdabcd
1.从左向右,最短匹配删除
格式:${变量名#*关键词}
删除从左侧第1个字符到最近的关键词
例:echo ${a#*c}
结果为:dabcd
2.从左向右,最长匹配删除
格式:${变量名##*关键词}
删除从左侧第1个字符到最远的关键词
例:echo ${a##*c}
结果为:d
3.从右向左,最短匹配删除
格式:${变量名%关键词*}
删除从右侧最后1个字符到往左最近的关键词
例:echo ${a%c*}
结果为:abcdab
4.从右向左,最长匹配删除
格式:${变量名%%关键词*}
删除从右侧最后1个字符到往左最远的关键词
例:echo ${a%%c*}
结果为:ab
字符串初值的处理
定义变量初值(备用值)
${变量名:-初值} #若变量已存在且非空,则返回变量原本的值;若变量为空,则自动调用初值
正则表达式
基本正则列表
^ 匹配行首
$ 匹配行尾
[ ] 集合,匹配集合中的任意单个字符
[^] 对集合取反
. 匹配任意单个字符
* 匹配前一个字符任意次数[*不允许单独使用]
\{n,m\} 匹配前一个字符n到m次
\{n,\} 匹配前一个字符n次及以上
\{n\} 匹配前一个字符n次
\(\) 组合为整体,保留
扩展正则列表
+ 至少匹配一次
? 最多匹配一次(0次或1次)
{n,m} 匹配前一个字符n到m次
( ) 组合为整体,保留
| 或者
\b 单词边界 例:\b单词\b
grep -E = egrep #允许使用扩展准则
grep -q #不显示所有常规输出(黑洞)
perl 正则
grep -P "\w" #匹配字母数字下划线
grep -P "\d" #匹配数字=[0-9]
grep -P "\s" #匹配空白(可以匹配空格,tab键)
sed工具
格式:sed [选项] "条件指令" 文件
- 条件可以是行号或者/正则/,没有条件时默认为所有行都执行指令
- 指令可以是p输出、d删除、s替换、c替换(整行)、i在前面插入一行、a在后面插入一行
sed命令的常用选项如下:
sed -i #修改文件内容
sed -n #屏蔽默认输出
sed -r #支持扩展正则
使用sed
1)行号案例
sed -n '2,4p' 文件 #输出2~4行
sed -n '2p;4p' 文件 #输出第2行与第4行
sed -n '3,+1p' 文件 #输出第3行以及后面1行
sed -n '1~2p' 文件 #输出奇数行
2)使用正则当条件
sed -n '/^root/p' 文件 #输出以root开头的行
sed -n '/root/p' 文件 #输出包含root的行
sed -nr '/^root|^bin/p' 文件 #输出以root开头的行或bin开头的行,|是扩展正则,需要r选项
3)特殊用法
sed -n '1!p' 文件 #输出除了第1行的内容,!是取反
sed -n '$p' 文件 #输出最后一行
sed -n '=' 文件 #输出行号,如果是$=就是最后一行的行号
sed工具的d、s、c、i、a操作指令
1)d指令删除
sed '3,5d' 文件 #删除第3~5行
sed '/xml/d' 文件 #删除所有包含xml的行
sed '/xml/!d' 文件 #删除不包含xml的行,!符号表示取反
sed '/^install/d' 文件 #删除以install开头的行
sed '$d' 文件 #删除文件的最后一行
sed '/^$/d' 文件 #删除所有空行
2)s指令替换基本功能(s/旧内容/新内容/选项)
sed 's/2017/6666/' 文件 #把所有行的第1个2017替换成6666
sed 's/2017/6666/2' 文件 #把所有行的第2个2017替换成6666
sed '1s/2017/6666/' 文件 #把第1行的第1个2017替换成6666
sed '3s/2017/6666/3' 文件 #把第3行的第3个2017替换成6666
sed 's/2017/6666/g' 文件 #所有行的所有个2017都替换
sed '/2024/s/2017/6666/g' 文件 #找含有2024的行,将里面的所有2017替换成6666
如果想把 /bin/bash 替换成 /sbin/sh 怎么操作?
sed 's/\/bin\/bash/\/sbin\/sh/' 文件 #使用转义符号可以成功,但不方便
sed 's!/bin/bash!/sbin/sh!' 文件 #最佳方案,更改s的替换符
sed 's(/bin/bash(/sbin/sh(' 文件 #替换符号可以用键盘上大部分字符
sed -r 's/([0-9]+)(\s+)([a-z]+)/\3\2\1/' abc.txt #使用替换功能更改文本列,此处小括号相当于保留(复制),\1相当于粘贴之前第1个小括号里的内容
3)c指令替换整行(c 新内容)
sed 'c 666' 文件 #所有行都替换成666
sed '1c 666' 文件 #替换第1行为666
sed '/^HISTSIZE/c HISTSIZE=2000' /etc/profile #替换以HISTSIZE开头的行为HISTSIZE=2000
4)i指令在前面插入一行(i 插入的内容)
sed 'i 666' 文件 #所有行的上面添加666
sed '5i 666' 文件 #第5行的上面添加666
sed '$i 666' 文件 #最后1行的上面添加666
sed '/^export/i HISTTIMEFORMAT="%F %T "' /etc/profile #在以export开头的行的上面插入HISTTIMEFORMAT="%F %T "
5)a指令在后面插入一行(a 插入的内容)
sed 'a 666' 文件 #所有行的下面追加666
sed '1a 666' 文件 #第1行的下面追加666
sed '/^bin/a 666' 文件 #在以bin开头的行的下面追加666
awk提取文本
awk的基本用法
格式1:awk [选项] '[条件]{指令}' 文件
格式2:前置指令 | awk [选项] '[条件]{指令}'
其中,print 是最常用的编辑指令;若有多条编辑指令,可用分号分隔。
awk过滤数据时支持仅打印某一列,如第2列、第5列等。
处理文本时,默认将空格、制表符作为分隔符。
条件可以用/ /的方式,与sed类似。
awk常用内置变量
$0 文本当前行的全部内容
$1 文本的第1列
$2 文本的第2列,以此类推
NR 文件当前行的行号
NF 文件当前行的列数(有几列)
awk常用的选项
awk -F ... #可指定分隔符
awk -F [:/] ... #awk还可以识别多种单个的字符,比如以“:”或“/”分隔
awk处理的时机
awk会逐行处理文本,支持在处理第一行之前做一些准备工作,以及在处理完最后一行之后做一些总结性质的工作。
格式为:awk [选项] 'BEGIN{指令} {指令} END{指令}' 文件
- BEGIN{ } 行前处理,读取文件内容前执行,指令执行1次。
- { } 逐行处理,读取文件过程中执行,指令执行n次。
- END{ } 行后处理,读取文件结束后执行,指令执行1次。
awk处理条件
1.使用正则设置条件
/正则/ ~ 包含 !~ 不包含
awk '$6~/bin/{print}' 文件 #输出第6列包含bin的行
awk '$6!~/bin/{print}' 文件 #输出第6列不包含bin的行
2.使用数值/字符串比较设置条件
比较符号:==(等于) !=(不等于) >(大于) >=(大于等于) <(小于) <=(小于等于)
awk '$3<3{print}' 文件 #输出第3列小于3的行
awk '$3<=3{print}' 文件 #输出第3列小于等于3的行
awk 'NR==2{print}' 文件 #输出第2行
awk 'NR>2{print}' 文件 #输出行号大于2的行
3.逻辑测试条件
|| 或
&& 并且
awk 'NR>=3&&NR<=5{print}' 文件 #找行号是3~5行
awk 'NR==2||NR==4{print}' 文件 #找行号是2或者4的行
awk 'NR==2||NR==40{print}' 文件 #如果只有一个条件满足就显示一个
4.数学运算
awk 'NR%2==0{print NR,$0}' 文件 #在条件中使用运算,找到将行号除以2余数等于0的行,然后输出该行的行号和所有列,相当于输出偶数行
awk数组
数组是一个可以存储多个值的变量,具体使用的格式如下:
定义数组的格式:数组名[下标]=元素值
调用数组的格式:数组名[下标]
awk 'BEGIN{a[1]=10;a[2]=20;print a[2],a[1]}' #使用awk测试数组,创建数组a,下标1对应值是10,下标2对应值是20,然后输出下标是2与下标是1的值
数组可以收集信息,但收集完了之后查看确不方便,可以用for循环实现。
for(变量名 in 数组名){print 变量名} #这个格式可以查看数组的所有下标
awk '{a[$1]++}END{for(i in a){print i,a[i]}}' shu.txt #使用逐行任务与数组收集文档shu.txt中的信息,然后在END任务中使用for循环显示所有数组a的下标与值
其它
egrep常用选项:
egrep -i #忽略字母大小写
egrep -v #条件取反
egrep -c #统计匹配的行数
egrep -q #静默、无任何输出;多用于检测
egrep -n #显示出匹配结果所在的行号
egrep --color #标红显示匹配字符
ss命令可以查看系统中启动的端口信息,该命令常用选项如下:
-n以数字格式显示端口号
-t显示TCP连接的端口
-u显示UDP连接的端口
-l显示服务正在监听的端口信息,如httpd启动后,会一直监听80端口
-p显示监听端口的服务名称是什么(也就是程序名称)
例如:ss -ntulp | grep nginx
输出重定向
> 重定向标准输出
2> 重定向错误输出
&> 重定向所有输出
>> 将输出以追加的方式重定向
输入重定向
< 符号,输入重定向,可以在后面需要跟文件名,这样让程序不再从键盘读取数据,而是从文件中读取数据。
<< 符号也称Here Document,代表你需要的内容在这里,某指令导入字符串时使用,而无需文件
例如:
mail -s test root << EOF
hello
test mail~
EOF
strings 查看动态文件
取随机十位字符:tr -cd '_a-zA-Z0-9' < /dev/urandom | head -c 10
sort排序:
sort -nr -k 2 #n表示用数字排序,r表示降序排序,k 2表示排序每行的第2列,默认排序是升序