shell脚本进阶

shell脚本进阶

1. bash条件判断

1.1 条件测试类型

  • 整数测试
  • 字符测试
  • 文件测试

1.2 条件测试的表达式

[ expression ]
[[ expression ]]
test expression

1.3 整数测试(双目)

-eq     //测试两个整数是否相等
-ne     //测试两个整数是否不等
-gt     //测试一个数是否大于另一个数
-lt     //测试一个数是否小于另一个数
-ge     //大于或等于
-le     //小于或等于
举例:
[root@redhat ~]# [ 1 -eq 2 ]
[root@redhat ~]# echo $?
1

1.4 字符测试

==      //等值比较,检查==两边的内容是否一致,==两边都要有空格
!=      //检查两边内容是否不一致,不一致为真,一致为假
=~      //左侧字符串是否能够被右侧的PATTERN所匹配到。此表达式应用于双中括号[[]]中
-z "string"     //测试指定字符串是否为空,空则为真,不空则为假
-n "string"     //测试指定字符串是否不空,不空则为真,空则为假
举例:
[root@redhat ~]# [ "abc" == "abcd" ]
[root@redhat ~]# echo $?
1
[root@redhat ~]# [ -z "hello" ]
[root@redhat ~]# echo $?
1
[root@redhat ~]# [ -z "" ]
[root@redhat ~]# echo $?
0
[root@redhat ~]# [ -n "hello" ]
[root@redhat ~]# echo $?
0
[root@redhat ~]# [ -n "" ]
[root@redhat ~]# echo $?
1

1.5 文件测试

//存在性测试:
    -e      //测试文件是否存在
    
举例:
[root@redhat ~]# [ -e apache.sh ]       //判断文件是否存在,存在则为真
[root@redhat ~]# echo $?
0
[root@redhat ~]# ls /opt
apr-1.7.4         apr-util-1.6.3         httpd-2.4.57
[root@redhat ~]# [ -e /opt/apache.sh ]  //判断文件是否存在,不存在则为假
[root@redhat ~]# echo $?
1

//存在性及类别测试:
    -b      //测试文件是否为块设备文件
    -c      //测试文件是否为字符设备文件
    -f      //测试文件是否为普通文件
    -d      //测试指定路径是否为目录
    -h      //测试文件是否为符号链接文件
    -L      //测试文件是否为符号链接文件
    -p      //测试文件是否为命名管道文件
    -S      //测试文件是否为套接字文件
    
举例:
[root@redhat ~]# [ -d apache.sh ]   //写实apache.sh是否为目录  
[root@redhat ~]# echo $?     //不为目录,判断为假
1
[root@redhat ~]# [ -f apache.sh ]   //写实apache.sh是否为文件
[root@redhat ~]# echo $?    //是文件,判断为真
0

//文件权限测试:
    -r      //测试当前用户对指定文件是否有读权限
    -w      //测试当前用户对指定文件是否有写权限
    -x      //测试当前用户对指定文件是否有执行权限
    
举例:
[root@redhat ~]# ll apache.sh       //当前用户为root
-rwxr-xr-x. 1 root root 3845 Sep  9 12:47 apache.sh

//root对该文件拥有读写执行的权限,所以三者都为真
[root@redhat ~]# [ -r apache.sh ]
[root@redhat ~]# echo $?
0
[root@redhat ~]# [ -w apache.sh ]
[root@redhat ~]# echo $?
0
[root@redhat ~]# [ -x apache.sh ]
[root@redhat ~]# echo $?
0

//文件特殊权限测试:
    -g      //测试文件是否有sgid权限
    -u      //测试文件是否有suid权限
    -k      //测试文件是否有sticky权限
    
举例:
[root@redhat ~]# ll -d /tmp
drwxrwxrwt. 12 root root 263 Sep 10 14:03 /tmp

[root@redhat ~]# [ -u /tmp ]
[root@redhat ~]# echo $?
1
[root@redhat ~]# [ -g /tmp ]
[root@redhat ~]# echo $?
1
[root@redhat ~]# [ -k /tmp ]
[root@redhat ~]# echo $?
0

//文件大小测试:
    -s      //测试文件是否非空,有内容则为真
    
举例:
[root@redhat ~]# cat ftx        //查看ftx文件,文件为空
[root@redhat ~]#

[root@redhat ~]# [ -s ftx ]
[root@redhat ~]# echo $?
1

//文件是否打开测试:
    -t fd   //fd表示的文件描述符是否已经打开且与某终端相关
//双目测试:
    file1 -ef file2     //测试file1与file2是否指向同一个设备上的相同inode,说白点就是两者是不是同一个文件
    file1 -nt file2     //测试file1是否比file2新
    file1 -ot file2     //测试file1是否比file2旧

举例:
[root@redhat ~]# ln apache.sh hehe.sh
[root@redhat ~]# ll
total 2240
-rw-------. 1 root root    1344 Jul  4 14:48 anaconda-ks.cfg
-rwxr-xr-x. 2 root root    3845 Sep  9 12:38 apache.sh
-rw-r--r--. 1 root root       0 Sep  9 23:45 ftx
-rwxr-xr-x. 2 root root    3845 Sep  9 12:38 hehe.sh
[root@redhat ~]# echo $?
0
[root@redhat ~]# [ apache.sh -ef ftx ]
[root@redhat ~]# echo $?
1

//无分类:
    -N      //测试文件自从上一次被读取之后是否被修改过
    -O      //测试文件是否存在并且被当前用户拥有
    -G      //测试文件是否存在并且默认组是否为当前用户组
    
举例:
[root@redhat ~]# cat ftx     //查看文件
[root@redhat ~]# [ -N ftx ]   //判断文件被修改没有
[root@redhat ~]# echo $?      //没有修改则为假
1
[root@redhat ~]# echo 'hello' >> ftx   //添加一行内容
[root@redhat ~]# [ -N ftx ]   //再次判断文件是否被修改
[root@redhat ~]# echo $?   //修改过后为真
0

[root@redhat ~]# [ -O ftx ]   //测试文件是否存在并且被当前用户拥有
[root@redhat ~]# echo $?    //此时为真
0

1.6 组合测试条件

-a      //与关系
-o      //或关系
!       //非关系

[ $# -gt 1 -a $# -le 3 ]
[ $# -gt 1 ] && [ $# -le 3 ]

1.7 条件判断,控制结构

1.7.1 单分支if语句
if 判断条件; then
    statement1
    statement2
    ......
fi

举例:
[root@redhat ~]# cat if.sh 
#!/bin/bash

# 提示用户输入两个数字
echo -e "
1. +
2. -
3. *
4. /
"
read -p "请输入第一个数字: " num1
read -p "请输入第二个数字: " num2
read -p "请输入运算方式: " yun


# 进行加法计算
if [ $yun -eq 1 ];then      判断当$yun变量等于1,执行下列运算
    sum=$(($num1 + $num2))
    echo "加法结果为: $sum"
fi
[root@redhat ~]# 
1.7.2 双分支if语句
if 判断条件; then
    statement1
    statement2
    ......
else
    statement3
    statement4
    ......
fi	
1.7.3 多分支if语句
if 判断条件1; then
    statement1
    statement2
    ......
elif 判断条件2; then
    statement3
    statement4
    ......
else
    statement5
    statement6
    ......
fi

举例:
[root@redhat ~]# ll chengji.sh
-rwxr-xr-x. 1 root root 238 Sep 10 00:08 chengji.sh
[root@redhat ~]# cat chengji.sh 
#!/bin/bash

read -p "输入你的成绩: " cj

if [ $cj -ge 90 ];then
    echo "优"
elif [ $cj -ge 80 ];then
    echo "良"
elif [ $cj -ge 70 ];then
    echo "中"
elif [ $cj -ge 60 ];then
    echo "及格"
else
    echo "不及格"
fi
[root@redhat ~]# ./chengji.sh 
输入你的成绩: 85
良

2. 分支选择

case $变量名 in            
value1)                
    statement                
    ...                
    ;;            
value2)                
    statement                
    ...                
    ;;            
*)                
    statement                
    ...                
    ;;        
esac

//case支持glob风格的通配符:
    *           //任意长度任意字符
    ?           //任意单个字符
    []          //指字范围内的任意单个字符
    abc|bcd     //abc或bcd
    
举例:
[root@CentOS8 ~]# vim httpd.sh 
[root@CentOS8 ~]# cat httpd.sh 
#!/bin/bash

case $1 in 
    start)                            //当$1为start时,执行systemctl start httpd命令
	    systemctl start httpd
	;;
    stop)
        systemctl stop httpd          //当$1为start时,执行systemctl stop httpd命令
	;;
    restart)
	    systemctl restart httpd       //当$1为start时,执行systemctl restart httpd命令
	;;
    status)
      ps -ef | grep -v "grep\|$0" | grep httpd &> /dev/null  //取出除本身进程以外的httpd的进程
	if [ $? -eq 0 ];then       //若有其他进程则为真(0),那脚本就会执行echo "httpd is started"
	    echo "httpd is started"
	else
            echo "httpd is stopped"   //若有其他进程则为假(不为0),那脚本就会执行echo "httpd is stopped"
        fi
	;;
    *)                             //当$1不是上面的所定义的字符,则会执行下列命令,提供正确的命令
	echo "Usage: service httpd start | stop | restart | status"
	;;
esac
[root@CentOS8 ~]# ./httpd.sh status    //此时查看状态,进程中没有其他关于httpd的进程
httpd is stopped

3. 循环语句

循环语句通常需要有一个进入条件和一个退出条件。

3.1 for循环

for循环当列表不为空时进入循环,否则退出循环

遍历有一个列表,把一个列表里面的一个个去取出来(注:不能用在列表中存在空格的场景下,他会把空格当做成是换行,在有空格的地方再次换行)

for 变量 in 列表; do
    循环体
done

for ((expr1;expr2;expr3))
{
    循环体
}

for (( expr1 ; expr2 ; expr3 ));do
    循环体
done

expr1   //用于指定初始条件,给控制变量一个初始值
expr2   //判定什么时候退出循环
expr3   //修正expr1指定的变量的值

举例:
[root@redhat ~]# cat for.sh 
#!/bin/bash

for ((i=1;i<=10;i++));do
    echo loop: $i
done
[root@redhat ~]# ./for.sh 
loop: 1
loop: 2
loop: 3
loop: 4
loop: 5
loop: 6
loop: 7
loop: 8
loop: 9
loop: 10
[root@redhat ~]# bash -x for.sh 
+ (( i=1 ))      //起始值i=1
+ (( i<=10 ))    //进行判断,满足进入循环的条件
+ echo loop: 1   打印结果
loop: 1
+ (( i++ ))      //新的一轮i的值自动加1
+ (( i<=10 ))    //再次进行判断
+ echo loop: 2
loop: 2
+ (( i++ ))
+ (( i<=10 ))
+ echo loop: 3
loop: 3
省略. . .

//如何生成列表:
    {1..10}
    seq [起始数] [步进长度] 结束数
    
举例:
[root@redhat ~]# seq 1 1 10    //起始值和步进长度不写的话默认为1
1
2
3
4
5
6
7
8
9
10

同时还有下列方法:
[root@redhat ~]# vim for.sh
[root@redhat ~]# chmod +x for.sh
[root@redhat ~]# cat for.sh 
#!/bin/bash

for i in {1..10};do
    echo loop: $i
done
[root@redhat ~]# ./for.sh 
loop: 1
loop: 2
loop: 3
loop: 4
loop: 5
loop: 6
loop: 7
loop: 8
loop: 9
loop: 10

3.2 while循环

while循环适用于循环次数未知的场景,注意要有退出条件。
条件满足时进入循环,条件不满足了退出循环。

3.2.1 while循环正常用法
while 条件; do
    statement
    ...
done

举例: 
[root@redhat ~]# vim while.sh
[root@redhat ~]# chmod +x while.sh 
[root@redhat ~]# cat while.sh 
#!/bin/bash

flag=true     //设置条件的变量,为真(true)则进入循环
i=1      //定义i的值为1

while $flag;do
    if [ $i -le 10 ];then         //当$1小于10时进行执行下列命令
        echo $i
    elif [ $i -gt 20 ] && [ $i -le 30 ];then  //若上述条件不满足则进行下一个判断,$i大于20小于30
	echo $i
    fi
    let i++                   //循环一轮自动加1
    if [ $i -gt 30 ];then     //如果大于30则执行flag=false,将条件的变量改为假,就可以退出循环
	flag=false
    fi
done
[root@redhat ~]# ./while.sh     //执行效果
1
2
3
4
5
6
7
8
9
10
21
22
23
24
25
26
27
28
29
30
3.2.2 while循环特殊用法
//while循环特殊用法一:死循环
while :;do
    statement
    ...
done

//这里的冒号可以改成任何非空值

举例:
[root@redhat ~]# vim while.sh
[root@redhat ~]# cat while.sh
#!/bin/bash

i=1   //定义i的起始值

while true;do    //当条件直接写为true时,那这个循环将永无止境,所以我们要今天条件判断使其在何时停止
    echo "ftx" $i
    let i++
    if [ $i -gt 10 ];then     //当$i大于10时执行下列命令
	echo "stop"
	break     //break在脚本中有ctrl+c 的作用
    fi
done
[root@redhat ~]# ./while.sh ]
ftx 1
ftx 2
ftx 3
ftx 4
ftx 5
ftx 6
ftx 7
ftx 8
ftx 9
ftx 10
stop


while循环特殊用法二:逐行读取某文件,将值存入line变量中
while read line;do
    statement
    ...
done < /path/to/somefile

[root@redhat ~]# vim while.sh 
[root@redhat ~]# cat while.sh
#!/bin/bash

while read line;do               //line变量代表的是读取的文件中的每一行内容
    echo $(echo $line | awk -F: '{print $1":"$NF}')  //打印出passwd文件中每行的第一个和最后一个
    echo =========================================   //用此符号进行分隔,方便查看
done < passwd
[root@redhat ~]# ./while.sh 
root:/bin/bash
=========================================
bin:/sbin/nologin
=========================================
daemon:/sbin/nologin
=========================================
adm:/sbin/nologin
=========================================
lp:/sbin/nologin
=========================================
sync:/bin/sync
=========================================

3.3 until循环

条件不满足时进入循环,条件满足了退出循环。(与while循环正好相反)

until 条件; do
    statement
    ...
done

3.4 循环语句特殊情况

在循环语句中,有几种特别情况:

break [num]:提前退出循环。当循环语句中出现break时,将提前退出循环,不再执行循环后面的语句

continue [num]:提前结束本轮循环而进入下一轮循环。当循环语句执行到continue时,continue后面的语句将不再执行,提前进入下一轮循环

4. 定义脚本退出状态码

//exit命令用于定义执行状态结果

exit #      //此处的#号是一个数字,其范围可以是0-255

如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码

注意:脚本中一旦遇到exit命令,脚本会立即终止
=============
lp:/sbin/nologin
=========================================
sync:/bin/sync
=========================================

3.3 until循环

条件不满足时进入循环,条件满足了退出循环。(与while循环正好相反)

until 条件; do
    statement
    ...
done

3.4 循环语句特殊情况

在循环语句中,有几种特别情况:

break [num]:提前退出循环。当循环语句中出现break时,将提前退出循环,不再执行循环后面的语句

continue [num]:提前结束本轮循环而进入下一轮循环。当循环语句执行到continue时,continue后面的语句将不再执行,提前进入下一轮循环

4. 定义脚本退出状态码

//exit命令用于定义执行状态结果

exit #      //此处的#号是一个数字,其范围可以是0-255

如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码

注意:脚本中一旦遇到exit命令,脚本会立即终止
  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个类似tree命令的shell脚本,满足题目的要求: ```bash #!/bin/bash # 定义一个递归函数,输出目录结构 function tree() { local dir=${1:-.} local prefix=${2:-""} local link="" local file="" local dir_list=() local link_list=() local file_list=() # 遍历当前目录下的所有文件和目录 for item in $(ls -1 "$dir"); do # 如果是目录,则输出目录名,并递归调用tree函数 if [ -d "$dir/$item" ]; then echo "${prefix}├── $item/" dir_list+=("$item") # 如果是链接,则输出链接名,并将链接目标作为新的dir调用tree函数 elif [ -L "$dir/$item" ]; then link=$(readlink "$dir/$item") echo "${prefix}├── $item -> $link" link_list+=("$item") # 如果是文件,则输出文件名 else echo "${prefix}├── $item" file_list+=("$item") fi done # 对于每个目录,递归调用tree函数 for dir_item in "${dir_list[@]}"; do tree "$dir/$dir_item" "${prefix}│ " done # 输出链接和文件的数量 if [ ${#link_list[@]} -gt 0 ]; then echo "${prefix}├── ${#link_list[@]} links" fi if [ ${#file_list[@]} -gt 0 ]; then echo "${prefix}└── ${#file_list[@]} files" fi } # 解析命令行参数 show_files=1 show_long=0 while getopts "fl" opt; do case $opt in f) show_files=0 ;; l) show_long=1 ;; \?) echo "Invalid option: -$OPTARG" >&2 echo "Usage: $(basename $0) [-f] [-l] [dir]" >&2 exit 1 ;; esac done shift $((OPTIND-1)) # 获取要显示的目录 dir=${1:-.} cd "$dir" || exit 1 # 输出目录结构 echo "$dir" if [ $show_files -eq 0 ]; then tree | grep --color=never "/$" else tree fi if [ $show_long -eq 1 ]; then echo "------------------------" ls -l fi ``` 该脚本实现了以下功能: 1. 可以显示指定目录下的目录结构。 2. 通过使用参数 `-f` 可以只显示目录,不显示文件。 3. 可以处理链接,输出链接名和链接目标。 4. 通过使用参数 `-l` 可以显示部分长信息。 使用示例: ```bash $ ./tree.sh -f /usr/local /usr/local ├── bin/ ├── etc/ ├── games/ ├── include/ ├── lib/ ├── man/ ├── sbin/ ├── share/ ├── src/ ├── var/ └── www/ $ ./tree.sh -l /usr/local /usr/local ├── bin/ ├── etc/ ├── games/ ├── include/ ├── lib/ ├── man/ ├── sbin/ ├── share/ ├── src/ └── var/ ------------------------ total 0 lrwxr-xr-x 1 root root 9 Nov 6 2019 bin -> ../sbin drwxr-xr-x 3 root root 3 Nov 6 2019 etc/ drwxr-xr-x 2 root root 2 Nov 6 2019 games/ drwxr-xr-x 2 root root 2 Nov 6 2019 include/ drwxr-xr-x 10 root root 9 Nov 6 2019 lib/ drwxr-xr-x 5 root root 5 Nov 6 2019 man/ lrwxr-xr-x 1 root root 9 Nov 6 2019 sbin -> ../bin drwxr-xr-x 5 root root 5 Nov 6 2019 share/ drwxr-xr-x 4 root root 4 Nov 6 2019 src/ drwxr-xr-x 2 root root 2 Nov 6 2019 var/ ``` 在使用时,可以通过修改定义函数 `tree` 的方式来实现更多的功能。例如,可以在输出目录结构时,对目录进行排序;或者在输出长信息时,使用不同的选项来显示更多的信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值