当前位置: 首页 > news >正文

Linux笔记14——shell编程基础-8

tr命令

1.替换大小写

[root@bogon ~]# echo "test 123" | tr 'a-z' 'A-Z'
TEST 123

2.删除空格

[root@bogon ~]# echo "tes t 1 2 3" | tr -d ' '  
test123

问题:接收用户输入,若输如的都是yes,都打印确定

#!/bin/bash
read -p "input your file:" file
file=$(echo $file | tr 'A-Z' 'a-z')
[ "$file" == yes ] && echo 确定 

sort命令

功能:对指定文件里的行进行排序,默认使用每行开头的第一个字符进行排序

语法:sort [选项] 文件名

  • -f:忽略大小写
  • -b:忽略每行前的空白部分
  • -n:以数值型进行排序,默认使用的是字符串类型排序
  • -r:反向排序
  • -u:删除重复行,不需要考虑重复行连续还是不连续
  • -t:指定分隔符,默认分隔符是制表符
  • -k n:指定使用第几列的内容进行排序,一般和-t结合使用

注:第n列如果都是数字,则默认使用数字的字符态进行排序

1.准备测试数据

[root@bogon ~]# cat sort.txt 
Cdm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

2.忽略大小写

[root@bogon ~]# sort -f sort.txt daemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

3.忽略大小写和空白行

[root@bogon ~]# sort -fb sort.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

4.去掉重复行

[root@bogon ~]# sort -fbu sort.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

5.冒号分隔符,第三列,从小到大

[root@bogon ~]# sort -t: -k 3 -n sort.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

6.以数值方向反向排序,从大到小

[root@bogon ~]# sort -t: -k 3 -nru sort.txt
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
Cdm:x:3:4:adm:/var/adm:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
root:x:0:0:root:/root:/bin/bash

uniq命令

功能:用来取消重复行,与sort -u功能是一样的

格式:uniq  [选项]  文件名

  • -i:忽略大小写
  • -c:在关键字旁显示该关键字出现的次数(一般针对行)

注:当重复行不连接时,uniq是不生效的,需要先排序,再执行

1.准备测试数据

[root@bogon ~]# cat uniq.txt 
linux 30
unix 20
windows 50
windows 50
Windows 50
Linux 30
windows 50

2.去重

[root@bogon ~]# uniq uniq.txt 
linux 30
unix 20
windows 50
Windows 50
Linux 30
windows 50
#比原来少了一样,只去掉了相邻重复的一行

3.想去除所有重复行,需要先排序

[root@bogon ~]# sort uniq.txt | uniq
linux 30
Linux 30
unix 20
windows 50
Windows 50
[root@bogon ~]# sort uniq.txt | uniq -c1 linux 301 Linux 301 unix 203 windows 501 Windows 50
[root@bogon ~]# sort uniq.txt | uniq -c | sort -rn3 windows 501 Windows 501 unix 201 Linux 301 linux 30

问题:获取当前系统用户的shell类型,并分类统计,按降序排序

[root@bogon ~]# awk -F: '{print $NF}' /etc/passwd | sort | uniq -c | sort -rn14 /sbin/nologin12 /bin/bash2 /usr/sbin/nologin1 /sbin/shutdown1 /sbin/halt1 /bin/sync

条件判断

1.按照文件类型进行判断

  • -b 文件:判断该文件是否存在,且为块设备文件
  • -c 文件:判断该文件是否存在,且为字符设备文件
  • -d 文件:判断该文件是否存在,且为目录
  • -e 文件:判断该文件是否存在
  • -f 文件:判断该文件是否存在,且为普通文件
  • -L 文件:判断该文件是否存在,且为符号链接文件
  • -p 文件:判断该文件是否存在,且为管道文件
  • -s 文件:判断该文件是否存在,且内容非空(有内容为真)
  • -S 文件:判断该文件是否存在,且为套接字文件
#使用[]或test进行判断,使用[]时与内容左右都需要有一个空格
#可以使用echo $?来检测判断的结果,0为真、1为假
[ -e /etc/passwd ]
echo $? -- 0
test -e /etc/new
echo $? -- 1
#也可以结合 && 和 || 来测试。
[ -e /etc/passwd ] && echo yes || echo no
[ -e /etc/new ] && echo yes || echo no
-----------------
#判断是文件还是目录
[ -f /root ] && echo yes || echo no
[ -d /root ] && echo yes || echo no#判断文件是否为空
touch test.txt
[ -s test.txt ] && echo yes || echo no
echo "test data" > test.txt
[ -s test.txt ] && echo yes || echo no#是软链接文件
[ -L /etc/rc.local ] && echo yes || echo no
cd /dev#块设备是I/O设备中的一类,是将信息存储在固定大小的块中,每个块都有自己的地址,还可以在设备的任意
位置读取一定长度的数据,例如U盘,SD卡
[ -b /dev/sr0 ] && echo yes || echo no
[ -b /dev/nvme0n1p1 ] && echo yes || echo no#字符设备是指在I/O传输过程中以字符为单位进行传输的设备例如键盘,打印机
[ -c /dev/stdin ] && echo yes || echo no
[ -c /dev/stdout ] && echo yes || echo no
[ -c /dev/zero ] && echo yes || echo no
[ -c /dev/null ] && echo yes || echo no测试选项 作用
-z 字符串 判断字符串是否为空(为空返回真)
-n 字符串 判断字符串是否为非空(非空返回真)
字符串1 == 字符串2 判断字符串1是否和字符串2相等(相等返回真)
字符串1 != 字符串2 判断字符串1是否和字符串2不相等(不相等返回真)#是套接字文件
[ -S /run/mcelog-client ] && echo yes || echo no
#是管道文件
[ -p /run/initctl ] && echo yes || echo no
--------------------------
=>同系统命令ll(ls -l)
-:普通文件
d:目录文件
b:块设备文件
c:字符设备文件
l:链接文件
p:管道文件套接字文件
s:套接字文件
----------
#上面所有的选项都是判2个条件,文件存在且为什么类型
即:判断一个文件是不是普通文件,赋值不同得到结果不同
$ filename=/etc/passwd
$ [ -f "$filename" ] && echo "是普通文件" || ( [ -e "$filename" ] && echo "不是普通
文件" || echo "不存在" )
#多层条件判断时结构复杂,可以换if结构进行判断
#一个字符串进行判断时
name=jimmy
age=""
unset sex
[ -z "$name" ] && echo yes || echo no --no
[ -z "$age" ] && echo yes || echo no --yes
[ -z "$sex" ] && echo yes || echo no --yes
=> 字符串没有定义和没有赋值结果都为空
-----------
#多个字符串进行比较时:
name=jimmy
age=""
[ "$name" == $age ] && echo yes || echo no
-bash: [: jimmy:需要一元表达式#每个变量要加引号,不然没定义或没赋值时报语法错
[ "$name" == "$age" ] && echo yes || echo no --yes
或:
[[ "$name" == $age ]] && echo yes || echo no
---------
=>[]和[[]]的区别:
1、[[]]会识别比较符号,若是二元比较符,即使一个值没定义或没赋值,也会自动转为空字符串;
2、[[]]支持的表达式比[]更多,如:在数值比较时支持>、<等符号;有符号=~判断包含,参见cat .bashrc
name=jimmy;[[ $name =~ "y" ]] && echo yes || echo no

问题:接收一个文件,判断它的类型

#!/bin/bashread -p "please input your filename:" fn
if [ ! -e $fn ]
thenecho "文件不存在"
elseif [ -b $fn ]thenecho "这是一个块设备文件"elif [ -c $fn ]thenecho "这是一个字符设备文件"elif [ -f $fn ]thenecho "这是一个普通文件"elseecho "不是以上类型"fi
fi

2.按照文件权限进行判断

  • -r 文件:判断文件是否存在,且拥有读权限
  • -w 文件:判断文件是否存在,且拥有写权限
  • -x 文件:判断文件是否存在,且拥有执行权限
  • -u 文件:判断文件是否存在,且拥有suid权限
  • -g 文件:判断文件是否存在,且拥有sgid权限
  • -k 文件:判断文件是否存在,且拥有sbit权限
ll -d /etc/passwd =>-rw-r--r--
[ -r /etc/passwd ] && echo yes || echo no
[ -w /etc/passwd ] && echo yes || echo no --跟当前登录人权限有关
[ -x /etc/passwd ] && echo yes || echo no
ll -d /usr/bin/passwd =>-rwsr-xr-x.
[ -u /usr/bin/passwd ] && echo yes || echo no --yes
[ -g /usr/bin/passwd ] && echo yes || echo no
[ -k /usr/bin/passwd ] && echo yes || echo no#特殊权限的文件
#含有SUID权限,即当用户执行文件时会以用户所有者的身份进行执行
ll -d /usr/bin/passwd =>-rwsr-xr-x. u+s
#含有SUID权限,即当用户执行文件时会以用户所有者的身份进行执行
ll -d /usr/bin/locate =>-rwx--s--x. g+s
#含有SBIT权限,即设置该权限的目录,只有文件的创建者、目录所有者和root可以删除自己文件
ll -d /tmp =>drwxrwxrwt. O+t

问题:判断文件的权限

#!/bin/bashread -p "please input a filename:" fnfor i in r w x u g k
doif [ -$i "$fn" ]thenecho "有$i权限"elseecho "没有$i权限"fi
done

3.两个文件间进行比较

  • 文件1 -nt 文件2:判断文件1的修改时间是否比文件2新
  • 文件1 -ot 文件2:判断文件1的修改时间是否比文件2旧
  • 文件1 -ef 文件2:判断文件1是否和文件2的inode号一致
#判断是否为硬链接
[root@localhost ~]# [ 1.txt -ef 2.txt ] && echo yes || echo no
yes

4.多重条件判断

  • 判断1 -a 判断2:逻辑与,都成立结果为真
  • 判断1 -o 判断2:逻辑或,有一个成立,最终结果就为真
  • ! 判断:逻辑非,对判断结果取反
#逻辑与
[root@localhost ~]# a=100
[root@localhost ~]# [ -n "$a" -a "$a" -gt 150 ] && echo yes || echo no
no
#逻辑或
[root@localhost ~]# b=150
[root@localhost ~]# [ "$b" -gt 150 -o "$b" -eq 150 ] && echo yes || echo no
yes
#逻辑非
[root@localhost ~]# c=200
[root@localhost ~]# [ ! -n "$c" ] && echo yes || echo no
no

5.[[]]和[]区别

  1. 若进行字符比较,使用到的变量可以不用写双引号,会自动识别变量个数
  2. 若进行数值比较,在[]支持的表达式外,还支持>,<,==,!=等
  3. 若进行逻辑关系比较,与[]不同(-a,-o,!),而是(&&,||,!)
  4. 进行字符串比较时,可进行模式匹配,支持通配符(如:[[ 3a == 3* ]]); 可进行包含匹配,支持正则(如:[[ "nihao" =~ "ni"]])
  5. 其他表达式含义同,如文件类型判断、文件权限判断、多条件判断

流程控制

编程中流程控制分三类:顺序结构、分支结构、循环结构

1.if条件判断

判断条件符合的情况:1.true;2.test或中括号中条件判断式的结果为0;3.命令执行的结果为0

单分支if条件判断语句

格式:
if [ 条件判断式 ]
then
程序
fi
或:
if [ 条件判断式 ];then
程序
fi

问题:若根分区使用率超过20%,打印红色超标,并发送邮件给root用户

[root@localhost ~]# cat use.sh 
#!/bin/bashusage=$(df -h | awk '$NF~/\/$/{print $(NF-1)}' | cut -d% -f1)
msg="根分区使用率超标,值是$usage%"if [ $usage -gt 10 ]
thenecho $msgdnf -y install postfix s-nail    #安装邮件软件包systemctl start postfix    #启动服务echo $msg | mail -s "gen warning" root
fi[root@localhost ~]# bash use.sh 
根分区使用率超标,值是12%
上次元数据过期检查:0:03:39 前,执行于 2025年09月02日 星期二 19时52分23秒。
软件包 postfix-2:3.5.9-24.el9.x86_64 已安装。
软件包 s-nail-14.9.22-6.el9.x86_64 已安装。
依赖关系解决。
无需任何处理。
完毕!
[root@localhost ~]# mail
s-nail version v14.9.22.  Type `?' for help
/var/spool/mail/root: 3 messages 1 new 2 unread1 root                  2025-09-02 19:52   20/719   "gen warning                                             "U  2 root                  2025-09-02 19:55   20/718   "gen warning                                             "
▸N  3 root                  2025-09-02 19:56   19/708   "gen warning 

双分支if条件语句

格式:

if [ 条件判断式 ]
then
条件成立时,执行的程序
else
条件不成立时,执行的另一个程序
fi

问题:监控服务,监控另一台机器上的httpd服务

#nmap
#功能:端口扫描命令,结果显示的端口一定是存活的
#格式:nmap -sT 域名或IP
#选项:-s 扫描  -T 扫描所有开启的TCP端口[root@localhost ~]# bash jiankong_http.sh 
上次元数据过期检查:0:18:40 前,执行于 2025年09月02日 星期二 19时52分23秒。
软件包 nmap-3:7.92-1.el9.x86_64 已安装。
依赖关系解决。
无需任何处理。
完毕!
please input you ip4:67   2025年 09月 02日 星期二 20:11:24 CST httpd is down!! #原脚本:
[root@localhost ~]# cat jiankong_http.sh 
#!/bin/bashdnf -y install nmap
read -p "please input you ip4:" ip
kai=$(nmap -sT 192.168.66.$ip | grep "http$" )
if [ -n "$kai" ]
thenecho -e "\e[32m $(date) httpd is ok! \e[0m"
elseecho -e "\e[31m $(date) httpd is down!! \e[0m"
fi

多分支if条件语句

if [条件判断式1]
then
当条件判断式1成立时,执行程序1
elif [条件判断式2]
then
当条件判断式2成立时,执行程序2
......(可加入更多elif条件)
else
当所有条件不成立时,最后执行此程序
fi

问题:接收一个分数,判:90-100优秀,80-90良好,70-80及格,70分以下不及格

#!/bin/bashread -p "input a score:" score
jiegou=`echo $score | sed 's/[0-9]//g'`
if [ -n "$jiegou" ]
thenecho "请输入纯数字"
elseif [ $score -gt 100 -o $score -lt 0 ]thenecho "请输入0-100之间的数"elif [ $score -ge 90 ]thenecho "优秀"elif [ $score -ge 80 ]thenecho "良好"elif [ $score -ge 70 ]thenecho "及格"elseecho "不及格"fi
fi

多分支case条件语句

语法:
case $变量名 in
“值1”)
如果$变量等于值1,则执行程序1
;;
“值2”)
如果$变量等于值2,则执行程序2
;;
....省略...
*)
如果$变量的值不是以上值,则执行此程序
;;
esac

注:只能进行一种条件的判断,会列出所有可能的值;case列出的值,可以是一个数字,一个字符串,或是|、通配符(* ? [])

问题:将之前的判断分数的多分支条件语句切换成case条件语句

#!/bin/bash
read -p "input a score:" score
case $score in
9[0-9]|100)echo 优秀;;
8[0-9])echo 良好;;
7[0-9])echo 及格;;
[0-9]|[1-6][0-9])echo 不及格;;
*)echo 请输入正确的分数;;
esac

2.for循环

语法一:
for 变量 in 值1 值2 值3 ...
do
执行程序
done
语法二:
for ((初始值;循环控制条件;变量变化))
do
执行程序
done

问题:打印九九乘法表

[root@localhost ~]# cat 9\*9.sh 
#!/bin/bashfor i in {1..9}
dofor((j=1;j<=$i;j++))doecho -ne $j*$i="$(($i*$j))\t"doneecho
done
[root@localhost ~]# bash 9\*9.sh 
1*1=1	
1*2=2	2*2=4	
1*3=3	2*3=6	3*3=9	
1*4=4	2*4=8	3*4=12	4*4=16	
1*5=5	2*5=10	3*5=15	4*5=20	5*5=25	
1*6=6	2*6=12	3*6=18	4*6=24	5*6=30	6*6=36	
1*7=7	2*7=14	3*7=21	4*7=28	5*7=35	6*7=42	7*7=49	
1*8=8	2*8=16	3*8=24	4*8=32	5*8=40	6*8=48	7*8=56	8*8=64	
1*9=9	2*9=18	3*9=27	4*9=36	5*9=45	6*9=54	7*9=63	8*9=72	9*9=81	

问题:输入一个值,打印对应几行的*符号

[root@localhost ~]# cat fuhao.sh 
#!/bin/bash
read -p "input a num:" num
for i in $(seq $num)
dofor j in $(seq $i)doecho -n "*"doneecho
done
[root@localhost ~]# bash fuhao.sh 
input a num:3
*
**
***
[root@localhost ~]# 

3.while循环

注:只要条件判断式成立,循环就会一直继续,直到条件不成立,循环才停止
语法:
while [ 条件判断式 ]
do
程序
done

问题:计算1+2+3+.....+100的值

#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
dolet sum+=$ilet i++
done
echo $sum

问题:持续监测远程服务器的httpd服务的状态

#!/bin/bashdnf -y install nmap
read -p "please input you ip4:" ip
while true
dokai=$(nmap -sT 192.168.66.$ip | grep "http$" )if [ -n "$kai" ]thenecho -e "\e[32m $(date) httpd is ok! \e[0m"elseecho -e "\e[31m $(date) httpd is down!! \e[0m"fisleep 10s
done

问题:随机产生一个数,猜数字

#!/bin/bashcou=$(($RANDOM%100+1))
while true
doread -p "please enter a num:" numif [ $num -lt $cou ]thenecho 小了elif [ $num -gt $cou ]thenecho 大了elseecho 猜中了breakfi
done

4.until循环

注:until循环和while循环相反,只要条件判断式不成立,则一直循环;直到条件成立则结束循环
格式:
until [ 条件判断式 ]
do
程序
done

例:计算从1+到100的和

su=0
j=1
until [ $j -gt 100 ]
dolet su+=$jlet j++
done
echo $su

5.异常流程控制

exit

  • 系统中的exit是退出当前登录,但在shell中是退出脚本,回到Linux命令行
  • 格式:exit [ 值 ]
  • exit 退出时如果定义好了返回值,那么我们可以通过“$?”来查看。如果exit命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。
  • 可以通过$?查询,来查看返回值,范围是0-255。如果exit之后没有定义返回值,脚本执行之后的返回值是执行exit之前,最后执行一条命令的返回值

break

  • break概述:跳出当前整个循环或结束当前循环,在for、while等循环语句中,用于跳出当前所在的循环体,执行循环体之后的语句;
  • 后面如果什么也不加,表示跳出当前循环等价于break 1,也可以在后面加数字,假设break 3表示跳出第三层循环

continue

  • continue概述:忽略本次循环剩余的代码,直接进行下一次循环;在for、while等循环语句中,用于跳出当次所在的循环,不终止循环,继续执行剩余循环

函数

在编写脚本时,有些语句会被重复使用多次。把这些可能重复使用的代码写成函数,这样我们通过
函数名称可以更高效的重复利用他们。如果想让自己写的脚本代码可以为别人所使用,同样需要函
数功能。
格式:
function 函数名() {
程序
}

#!/bin/bash
function demoFun(){
echo "这是我的第一个 shell 函数!"
}
echo "-----函数开始执行-----"
demoFun
echo "-----函数执行完毕-----"
----------------------
#定义一个求和函数,计算从1到用户输入数字的和
$ vim function.sh
#!/bin/bash
#定义函数
function sum () {
s=0
for (( i=0;i<=$1;i=i+1 ))
do
s=$(( $i+$s ))
done
echo "the sum of 1+2+3+..+$1 is :$s"
}
-------------
#本脚本直接调用该函数,继续写
$ vim function.sh
read -p "please input a number:" num
y=$(echo $num | sed 's/[0-9]//g')
if [ -z "$y" ]
then
sum $num
else
echo "error!!please input a number!"
fi
------
#其他脚本调用
$ cat diaoyong.sh
#!/bin/bash
#先用.或sourceh引入函数所在的脚本
. /root/function.sh
#再用函数名调用
read -p "please input a number:" num
y=$(echo $num | sed 's/[0-9]//g')
if [ -z "$y" ]
then
sum $num
else
echo "error!!please input a number!"
fi

http://www.xdnf.cn/news/1436563.html

相关文章:

  • C#类对象映射AutoMapper
  • QT(2)
  • MTK Linux DRM分析(二十九)- MTK mtk_dsi.c(Part.1)
  • Linux 环境配置 muduo 网络库详细步骤
  • Linux 文本处理三大利器:命令小工具和sed
  • 从理念到实践:三层解耦架构与“无系统”论
  • 基于web的高校学籍管理系统的设计与实现-(源码+LW+可部署)
  • CodeBuddy 在进化:我只输入了一个地址,完成了OneCode3.0基础开发环境的配置构建
  • JWT在线解密/JWT在线解码 - 加菲工具
  • kukekey在线搭建k8sV1.30.4版本
  • 从栈中取出K个硬币的最大面值和-分组背包
  • 【学Python自动化】 8. Python 错误和异常学习笔记
  • 2025年工科生职业发展证书选择与分析
  • 【模型学习】LoRA的原理,及deepseek-vl2下LoRA实现
  • 力扣242:有效的字母异位词
  • JetBrains 2025 全家桶 11合1 Windows直装(含 IDEA PyCharm、WebStorm、DataSpell、DataGrip等
  • C++类和对象(中)- 默认成员函数
  • 什么是数据库管理系统(DBMS)?RDBMS和NoSQL又是什么?
  • 第 2 讲:Kafka Topic 与 Partition 基础
  • Qwen3-Embedding-0.6B 模型结构
  • Go结构体详解:核心概念与实战技巧
  • Redis-底层数据结构篇
  • MySQL-表的约束(上)
  • 开发中使用——鸿蒙本地存储之收藏功能
  • LLM 能不能发展为 AGI?
  • 开源模型应用落地-模型上下文协议(MCP)-构建AI智能体的“万能插座”-“mcp-use”高级用法(十三)
  • 3.2-C++基础组件
  • 重新审视信任基石:公网IP证书对网络安全生态的影响
  • 【Go语言入门教程】 Go语言的起源与技术特点:从诞生到现代编程利器(一)
  • Cursor 教我学 Python