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/nologin
	daemon: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/nologin
	daemon: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/nologin
	daemon: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/nologin
	daemon: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/nologin
	daemon: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 -c
      1 linux 30
      1 Linux 30
      1 unix 20
      3 windows 50
      1 Windows 50
[root@bogon ~]# sort uniq.txt | uniq -c | sort -rn
      3 windows 50
      1 Windows 50
      1 unix 20
      1 Linux 30
      1 linux 30

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

复制代码
[root@bogon ~]# awk -F: '{print $NF}' /etc/passwd | sort | uniq -c | sort -rn
     14 /sbin/nologin
     12 /bin/bash
      2 /usr/sbin/nologin
      1 /sbin/shutdown
      1 /sbin/halt
      1 /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/bash

read -p "please input your filename:" fn
if [ ! -e $fn ]
then
        echo "文件不存在"
else
        if [ -b $fn ]
        then
                echo "这是一个块设备文件"
        elif [ -c $fn ]
        then
                echo "这是一个字符设备文件"
        elif [ -f $fn ]
        then
                echo "这是一个普通文件"
        else
                echo "不是以上类型"
        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/bash

read -p "please input a filename:" fn

for i in r w x u g k
do
        if [ -$i "$fn" ]
        then
                echo "有$i权限"
        else
                echo "没有$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/bash

usage=$(df -h | awk '$NF~/\/$/{print $(NF-1)}' | cut -d% -f1)
msg="根分区使用率超标,值是$usage%"

if [ $usage -gt 10 ]
then
	echo $msg
	dnf -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 unread
    1 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/bash

dnf -y install nmap
read -p "please input you ip4:" ip
kai=$(nmap -sT 192.168.66.$ip | grep "http$" )
if [ -n "$kai" ]
then
	echo -e "\e[32m $(date) httpd is ok! \e[0m"
else
	echo -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/bash

read -p "input a score:" score
jiegou=`echo $score | sed 's/[0-9]//g'`
if [ -n "$jiegou" ]
then
        echo "请输入纯数字"
else
        if [ $score -gt 100 -o $score -lt 0 ]
        then
                echo "请输入0-100之间的数"
        elif [ $score -ge 90 ]
        then
                echo "优秀"
        elif [ $score -ge 80 ]
        then
                echo "良好"
        elif [ $score -ge 70 ]
        then
                echo "及格"
        else
                echo "不及格"
        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/bash

for i in {1..9}
do
	for((j=1;j<=$i;j++))
	do
		echo -ne $j*$i="$(($i*$j))\t"
	done
	echo
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)
do
	for j in $(seq $i)
	do
		echo -n "*"
	done
	echo
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 ]
do
        let sum+=$i
        let i++
done
echo $sum

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

复制代码
#!/bin/bash

dnf -y install nmap
read -p "please input you ip4:" ip
while true
do
        kai=$(nmap -sT 192.168.66.$ip | grep "http$" )
        if [ -n "$kai" ]
        then
                echo -e "\e[32m $(date) httpd is ok! \e[0m"
        else
                echo -e "\e[31m $(date) httpd is down!! \e[0m"
        fi
        sleep 10s
done

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

复制代码
#!/bin/bash

cou=$(($RANDOM%100+1))
while true
do
        read -p "please enter a num:" num
        if [ $num -lt $cou ]
        then
                echo 小了
        elif [ $num -gt $cou ]
        then
                echo 大了
        else
                echo 猜中了
                break
        fi
done

4.until循环

注:until循环和while循环相反,只要条件判断式不成立,则一直循环;直到条件成立则结束循环

格式:

until [ 条件判断式 ]

do

程序

done

例:计算从1+到100的和

复制代码
su=0
j=1
until [ $j -gt 100 ]
do
        let su+=$j
        let 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
相关推荐
空山新雨(大队长)2 小时前
HTML第二课:块级元素
前端·javascript·html
dreams_dream2 小时前
HTML 标签
前端·html
skywalk81632 小时前
mayfly-go:web 版 linux、数据库等管理平台
linux·运维·数据库
dbdr09012 小时前
Linux 入门到精通,真的不用背命令!零基础小白靠「场景化学习法」,3 个月拿下运维 offer,第二十四天
linux·运维·c语言·python·学习
烟雨迷2 小时前
web自动化测试(selenium)
运维·开发语言·前端·python·selenium·测试工具
wow_DG3 小时前
【Vue2 ✨】Vue2 入门之旅(九):Vue Router 入门
前端·javascript·vue.js
绵绵细雨中的乡音3 小时前
简易TCP网络程序
linux·网络
OpenTiny社区3 小时前
“AI 乱炖等于没 AI?”这些AI知识图谱教你秒锁正确场景
前端·开源·agent
维维酱4 小时前
useMemo 实现原理
前端·react.js