shell脚本编程

news/2024/9/25 11:10:18

目录
  • 一、什么是shell
    • 1、简介
    • 2、常见的shell
    • 3、查看当前正在使用的shell
  • 二、shell脚本注意事项
    • 1、Shebang行
    • 2、注释
    • 3、缩进
    • 4、日志与回显
  • 三、如何执行shell脚本
    • 1、source
    • 2、bash/sh/zsh
    • 3、./
  • 四、shell变量
    • 1、系统变量
    • 2、自定义变量
      • 2.1、变量定义的规则
      • 2.2、定义变量
      • 2.3、赋值时使用的符号
        • 2.3.1、使用双引号""
        • 2.3.2、使用单引号''
        • 2.3.3、使用反引号``
        • 2.3.4、使用$()
        • 2.3.5、区别
      • 2.4、给变量重新赋值
      • 2.5、撤销变量的值
      • 2.6、静态变量
      • 2.7、全局变量
    • 3、特殊变量
  • 五、逻辑判断运算符
    • 1、文件测试运算符
      • 1.1、存在性及类型测试:
      • 1.2、文件权限测试:
      • 1.3、文件特殊权限测试:
      • 1.4、文件大小测试:
      • 1.5、文件是否打开:
      • 1.6、双目测试:
    • 2、字符串比较运算符
    • 3、数值比较运算符
    • 4、逻辑运算符
  • 六、流程控制
    • 1、条件选择执行语句if
      • 1.1、单分支结构
        • 1.1.1、示例:检查文件是否存在
      • 1.2、双分支结构
        • 1.2.1、示例:判断数字奇偶
      • 1.3、多分支结构
        • 1.3.1、示例:成绩等级判定
    • 2、for循环语句
      • 2.1. 列表遍历形式
        • 2.1.1、示例:遍历数字列表、文件、命令
      • 2.2、 序列生成形式(使用seq或brace expansion)
        • 2.2.1、示例:生成序列
      • 2.3、 C风格的for循环
        • 2.3.1、示例:生成序列
    • 3、while循环语句
      • 3.1、标准格式
        • 3.1.1、示例:基础计数循环
      • 3.2、结合read逐行处理文件
        • 3.2.1、示例:读文件行
    • 4、until循环语句
      • 4.1示例:计数到5
    • 5、select循环语句
    • 6、case语句
      • 6.1、示例:星期几
    • 7、continue语句
      • 7.1、示例
      • 7.2、注意事项
    • 8、break语句
      • 8.1、单层循环跳出
      • 8.2、多层循环跳出
  • 七、数组
    • 1、索引数组(数值索引)
      • 1.1、定义与赋值
      • 1.2、访问元素
      • 1.3、读取数组
      • 1.4、获取数组长度
      • 1.5、遍历数组
      • 1.6、删除数组元素
        • 1.6.1、删除数组所有元素
        • 1.6.2、删除数组中的指定元素
    • 2、关联数组(字符串索引)
      • 2.1、定义与赋值
      • 2.2、访问元素
      • 2.3、获取数组长度
      • 2.4、遍历函数
      • 2.5、删除数组元素
  • 八、函数
    • 1、函数的格式
      • 1.1、格式一
      • 1.2、格式二
    • 2、参数传递
    • 3、返回值
  • 九、用户交互(read)
    • 1、基本用法
    • 2、显示提示信息,等待用户输入(-p)
    • 3、限制等待时间(-t)
    • 4、启用行编辑功能(-e)
    • 5、指定读取的字符数(-n)
    • 6、静默模式(-s)
    • 7、指定输出结束的分隔符(-d)
    • 8、数组赋值(<<<)
  • 十、调试脚本
    • 1、-x进行命令追踪
    • 2、-v查看命令和结果
    • 3、-n进行语法检查
    • 4、-e进行错误处理
    • 5、查看脚本的退出状态码
  • 十一、shell脚本实战

一、什么是shell

1、简介

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。 Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

简单来说,Shell就是用户与操作系统之间的命令解释器

image-20240509233348028

2、常见的shell

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

我们关注Bash,由于易用和免费,Bash在日常工作中被广泛使用

同时,Bash 也是大多数Linux 系统默认的 Shell。

3、查看当前正在使用的shell

1、查看环境变量

echo $SHELL

image-20240510165350996

2、通过进程信息查看

ps | grep $$ | awk '{print $4}'

image-20240510170523729

3、/etc/passwd文件查看

grep ^$(whoami) /etc/passwd | awk -F "/" '{print $4}'

image-20240510170755346

二、shell脚本注意事项

1、Shebang行

#!后面紧接解释器的绝对路径例如,使用bash时应在脚本第一行指明:
#!/bin/bash

2、注释

注释本质上还是为了增加脚本的可读性

注释包括以下部分:

shebang
脚本的参数
脚本的用途
脚本的注意事项
脚本的写作时间,作者,版权等
各个函数前的说明注释
一些较复杂的单行命令注释

3、缩进

#常见的缩进有"soft tab"和"hard soft"两种# soft tab就是使用n个空格进行缩进(n通常是2或4)# hard tab就是指真实的”\t”字符

4、日志与回显

#添加日志信息方便我们后续排查错误
#展现在终端的内容可以通过重定向选择性的展示,只保留重要的信息等

三、如何执行shell脚本

1、source

source Filename

在当前shell中执行

脚本文件无需可执行权限

2、bash/sh/zsh

bash Filename
sh Filename
zsh Filename
......

使用各自的命令解释器执行文件

子shell环境执行脚本

脚本文件无需可执行权限

3、./

#两种情况#第一种情况(执行当前目录下的脚本文件)
./Filename#第二种情况(脚本文件的绝对路径)
./Path/to/Filename

都需要脚本文件具有可执行权限

第一种情况在子shell环境下执行

第二种情况在当前shell环境下执行

四、shell变量

1、系统变量

#查看系统变量和用户定义的变量
set#显示环境变量命令,可以查到全局变量
env#显示环境变量命令,可以查到全局变量
printenv
系统变量 作用
$HOME 用户的主目录
$PWD 当前工作目录的绝对路径
$USER$LOGNAME 当前用户的用户名
$SHELL 当前用户的默认Shell
$PATH 查找可执行文件的路径列表,以冒号为分割
$RANDOM 生成一个随机数
$SECONDS Shell启动后经过的秒数
$TERM 打印当前的终端类型
$HOSTNAME 显示当前主机名
RANDOM 生成随机(0-32767)整数

2、自定义变量

2.1、变量定义的规则

  • 变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写
  • 不能使用特殊字符、标点符号、bash中的关键字
  • 等号两侧不能有空格
  • 在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
  • 变量的值如果有空格,需要使用双引号或者单引号括起来

2.2、定义变量

等号两侧不能有空格

格式:变量名=值

user_name=misaki
echo $user_name

image-20240511101721286

验证了等号两侧不能有空格

2.3、赋值时使用的符号

2.3.1、使用双引号""
[root@localhost ~]# name=misaki
[root@localhost ~]# TEXT="hello $name"
[root@localhost ~]# echo $TEXT
hello misaki

image-20240511105946713

2.3.2、使用单引号''
[root@localhost ~]# test='ls -1'
[root@localhost ~]# echo $test
ls -1

image-20240511111650329

2.3.3、使用反引号``
[root@localhost ~]# test=`ls -1`
[root@localhost ~]# echo $test
anaconda-ks.cfg

image-20240511110956302

2.3.4、使用$()
[root@localhost ~]# test=$(ls -1)
[root@localhost ~]# echo $test
anaconda-ks.cfg

image-20240511111013537

2.3.5、区别
1、双引号允许变量扩展和命令替换发生,但保留内部的空白字符(如空格和制表符)2、单引号阻止所有形式的扩展和解析,因此$(ls -1)被视为普通文本而非命令。3、反引号与$(...)功能相同,执行命令替换。但现代Shell脚本推荐使用$(...),因为它在嵌套和与其它引号配合使用时更清晰。

2.4、给变量重新赋值

只需再次使用相同的变量名并赋予新的值即可给已经存在的用户自定义变量重新赋值

[root@localhost ~]# user_name=zhangsan
[root@localhost ~]# echo $user_name
zhangsan
[root@localhost ~]# user_name=lisi
[root@localhost ~]# echo $user_name
lisi

image-20240511113306929

2.5、撤销变量的值

格式:unset 变量

[root@localhost ~]# unset user_name
[root@localhost ~]# echo $user_name

image-20240511113749869

2.6、静态变量

格式:readnoly 变量

静态变量不能unset(撤销)

[root@localhost ~]# readonly n1=1
[root@localhost ~]# echo $n1
1
[root@localhost ~]# unset n1
-bash: unset: n1: 无法反设定: 只读 variable

image-20240511122500040

2.7、全局变量

格式:export 变量名
可以通过这种方法把变量提升为全局变量,可供其它Shell程序使用

[root@localhost ~]# name=misaki
[root@localhost ~]# echo $name
misaki
[root@localhost ~]# bash
[root@localhost ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       8164   8160  0 12:42 pts/1    00:00:00 -bash
root       8193   8164  0 12:43 pts/1    00:00:00 bash
root       8204   8193  0 12:43 pts/1    00:00:00 ps -f
[root@localhost ~]# echo $name[root@localhost ~]# exit
exit
[root@localhost ~]# export name
[root@localhost ~]# bash
[root@localhost ~]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       8164   8160  0 12:42 pts/1    00:00:00 -bash
root       8205   8164  0 12:43 pts/1    00:00:00 bash
root       8216   8205  0 12:43 pts/1    00:00:00 ps -f
[root@localhost ~]# echo $name
misaki

image-20240511124447714

最开始在父shell中声明了变量name值为misaki
随后启动子shell打印输出变量name的值发现没有
紧接着回到父shell中将变量name提升为全局变量
最后再启动子shell打印变量name发现在和父shell中输出的值一样

3、特殊变量

特殊变量 功能
$0 当前脚本的文件名
$1, $2, ..., $n 传递给脚本的参数,其中 n 代表参数的位置,从1开始计数
$# 传递给脚本的参数个数
$* 将所有参数的内容看成一个整体返回
$$ 当前Shell脚本的进程ID(PID)
$! 最后一个后台进程的PID
$? 上一个命令或函数的退出状态码(0表示成功,非0表示失败)

五、逻辑判断运算符

1、文件测试运算符

用于检查与文件相关的条件,也适用于目录和其他类型的文件测试。

1.1、存在性及类型测试:

  • ‐a FILE :文件存在性测试,存在为真,否则为假
  • ‐b FLIE:是否存在且为块设备文件;
  • ‐c FILE:是否存在且为字符设备文件;
  • ‐d FILE:是否存在且为目录文件;
  • ‐f FILE:是否存在且为普通文件;
  • ‐h FILE 或 ‐L FILE : 存在且为符号链接文件;
  • ‐p FIEL :是否存在且为命名管道文件;
  • ‐S FILE:是否存在且为套接文件;

1.2、文件权限测试:

  • ‐r FILE:是否存在且可读
  • ‐w FILE:是否存在且可写
  • ‐x FILE:是否存在可执行

1.3、文件特殊权限测试:

  • ‐u FILE:是否存在且拥有suid权限;
  • ‐g FILE:是否存在且拥有sgid权限;
  • ‐k FILE:是否存在且拥有sticky权限;

1.4、文件大小测试:

  • ‐s FILE:是否存在且非空

1.5、文件是否打开:

  • ‐fd:fd表示文件描述符是否已经打开且与某终端相关
  • ‐N FILE:文件自动上一次读取之后是否被修改过;
  • ‐O FILE:当前用户是否为文件的属主;
  • ‐G FILE:当前有效用户是否为文件数组;

1.6、双目测试:

  • FILE1 ‐ef FILE2 :FILE1与FILE2是否指向同一个设备上的相同inode
  • FILE1 ‐nt FILE2:FILE1是否新于FILE2
  • FILE1 ‐ot FILE2:FILE1是否旧于FILE2

2、字符串比较运算符

==:是否等于 >:是否大于 <:是否小于!=:是否不等于 =~:左侧字符串是否能够被右侧的PATTERN所匹配,此表达式一般用于[[ ]]中 ‐z "STRING":测试字符串是否为空,空则为真,不空则为假 ‐n "STRING":测试字符串是否不空,不空则为真,空则为假

3、数值比较运算符

  • ‐gt:是否大于
  • ‐ge:是否大于等于
  • ‐eq:是否等于
  • ‐ne:是否不等于
  • ‐lt:是否小于
  • ‐le:是否小于等于

4、逻辑运算符

  • &&代表的意思是当前一个命令执行成功时会继续执行后续的命令,当前一个命令执行失败的时候不会执行后续的命令
  • ||代表的意思是当前一个命令执行成功时不会继续执行后续的命令,当前一个命令执行失败的时候会执行后续的命令
  • ! expr:如果expr的结果为假,则为真。
  • expr1 -a expr2:如果expr1和expr2都为真,则为真(逻辑与)。
  • expr1 -o expr2:如果expr1或expr2至少有一个为真,则为真(逻辑或)。

六、流程控制

1、条件选择执行语句if

1.1、单分支结构

if [ 条件表达式 ]; then条件为真时执行的命令
fi
1.1.1、示例:检查文件是否存在
#!/bin/bash
if [ -f "/etc/passwd" ]; thenecho "The file exists."
fi

image-20240512091856539

1.2、双分支结构

if [ 条件表达式 ]; then条件为真时执行的命令
else条件为假时执行的命令
fi
1.2.1、示例:判断数字奇偶
#!/bin/bash
read -p "输入一个数字:" num
if [ $((num % 2)) -eq 0 ]; thenecho "输入的数字是偶数"
elseecho "输入的数字是奇数"
fi

image-20240512093250906

1.3、多分支结构

if [ 条件表达式1 ]; then条件1为真时执行的命令
elif [ 条件表达式2 ]; then条件1为假且条件2为真时执行的命令
else所有条件均为假时执行的命令
fi
1.3.1、示例:成绩等级判定
#!/bin/bash
read -p "输入你的成绩:" sorce
if [ "$sorce" -ge 90 ]; thenecho "Grade: A"
elif [ "$sorce" -ge 80 ]; thenecho "Grade: B"
elif [ "$sorce" -ge 70 ]; thenecho "Grade: C"
elif [ "$sorce" -ge 60 ]; thenecho "Grade: D"
elseecho "Grade: F"
fi

image-20240512100045053

2、for循环语句

2.1. 列表遍历形式

for 变量名 in 列表
do命令序列
done
  • 变量名:在每次循环中用来存储当前遍历到的值。
  • 列表:可以是逗号分隔的值列表、文件名通配符(如*)、命令的输出(用反引号...$(...)包裹),或是任何能产生多个项目的序列。
2.1.1、示例:遍历数字列表、文件、命令
#!/bin/bash
#遍历数字列表
for i in 1 2 3 4 5
doecho $i
done
#遍历文件
for file in *.sh
doecho "Processing file: $file"
done
#遍历命令输出
for ip in $(hostname -I)
doecho "IP address: $ip"
done

image-20240512101046884

2.2、 序列生成形式(使用seq或brace expansion)

for 变量名 in $(seq 起始值 步长 结束值) 或 {起始值..结束值}
do命令序列
done
2.2.1、示例:生成序列
#!/bin/bash
#使用seq生成序列
echo for_seq
for i in $(seq 1 2 10)
doecho $i
done
#使用brace expansion
echo for_brace expansion
for n in {1..5}
doecho $n
done

image-20240512101727721

2.3、 C风格的for循环

for (( 表达式1; 表达式2; 表达式3 ))
do命令序列
done
  • 表达式1:初始化部分,通常用于设置循环变量的初始值。
  • 表达式2:条件表达式,当其值为真(非零)时继续循环。
  • 表达式3:更新部分,每次循环后执行,常用于改变循环变量的值。
2.3.1、示例:生成序列
#!/bin/bash
for (( i=1;i<5;i++ ))
doecho $i
done
[root@localhost Shell]# bash for_3.sh
1
2
3
4

image-20240512103306897

3、while循环语句

3.1、标准格式

while [条件表达式 ];
do命令序列
done
  • 条件表达式:一个命令或表达式,其退出状态决定循环是否继续。如果表达式的退出状态为0(真),则循环继续;否则,循环终止。
  • 命令序列:在每次循环中执行的命令集合。这些命令可以是一条或多条语句,通常用于改变循环控制变量的值,以确保循环最终能够结束,防止死循环。
3.1.1、示例:基础计数循环
#!/bin/bash
i=1
while [ $i -le 5 ]
doecho "This is loop number $i"i=$((i+1)) # 或 ((i++))
done

image-20240512103753911

3.2、结合read逐行处理文件

while read line; do循环体
done < /PATH/FROM/SOMEFILE

从标准输入读取文件中的每一行,并将其赋值给变量line

3.2.1、示例:读文件行
#!/bin/bash
count=0
while IFS= read -r line
dolet count+=1echo " Line$count: $line"
done < /etc/passwd

image-20240512104948695

4、until循环语句

until循环会重复执行一系列命令,直到给定的条件变为真(即条件表达式的退出状态为0。

确保until循环中的条件最终能够变为真,以避免创建无限循环。

until [条件表达式]
do命令序列
done

4.1示例:计数到5

#!/bin/bash
i=0
until [ $i -ge 5 ]
doecho "Counter: $i"i=$((i+1))
done

image-20240512105758976

5、select循环语句

select语句一般用于选择,常用于创建选择菜单系统,让用户能够在命令行界面中进行选择。

select循环会显示一个由选项组成的列表,并允许用户输入对应数字来选择一个选项。

select 变量名 in 列表; do命令序列
done

6、case语句

case语句是一种多路分支控制结构,用于根据不同的条件执行不同的代码块。

它类似于其他编程语言中的switch语句,提供了一种优雅的方式来处理多条件判断。

case 变量或表达式 in模式1)命令序列1;;模式2)命令序列2;;...*)默认命令序列(如果没有任何模式匹配时执行);;
esac
  • *):特殊模式,代表默认分支,当没有其他模式匹配时执行。
  • ;;:每个命令序列的结束标记。
  • esac:结束case语句的关键字,必须放在所有分支之后。
#结合select,case比较完整的类菜单格式如下:select 变量名 in 列表; docase $变量名 in选项1)相应的命令序列;;选项2)其他命令序列;;*)默认或无效选项处理;;esac
done

6.1、示例:星期几

#!/bin/bashday_of_week=$(date +%u) # %u 返回1(星期一) 到7(星期日)# 通过case语句匹配今天的星期并输出对应信息
case $day_of_week in1)echo "今天是星期一,一周的开始,努力工作!";;2)echo "星期二,继续加油!";;3)echo "过了星期三,翻过一座山,星期三愉快!";;4)echo "星期四,期待周末的到来!";;5)echo "星期五,马上就是周末啦,坚持一下!";;6|7) # 星期六和星期日一起处理echo "周末啦,好好休息,享受生活!";;*)echo "无法识别的日期格式,请检查date命令是否正常工作。";;
esac# 脚本执行完case语句后自动退出
exit 0

image-20240512113742776

7、continue语句

continue语句是一个流程控制命令,用于跳过当前循环迭代中剩余的部分命令,直接开始下一次循环迭代(如果条件仍允许循环继续的话)

7.1、示例

假设我们有一个脚本,想要打印1到10之间的数字,但跳过偶数:

#!/bin/bash
for i in {1..10}; doif [ $((i % 2)) -eq 0 ]; thencontinuefiecho $i
done

image-20240511232407941

7.2、注意事项

  • 作用范围continue只影响最直接包围它的循环。如果在嵌套循环中使用continue,它只会跳过当前层次循环的剩余部分,不会影响外层循环。
  • 与break的区别break语句会立即终止整个循环,而不仅仅是当前迭代,直接跳出循环体。
  • 使用场景continue常用于在满足特定条件时略过循环体中某些不必要的操作,而继续执行后续的迭代,这对于过滤或跳过某些循环过程中的情况非常有用。

8、break语句

break语句是一个流程控制命令,用于提前退出循环结构,包括forwhileuntil循环以及select语句。

8.1、单层循环跳出

#!/bin/bash
for i in {1..5}; doif [ $i -eq 3 ]; thenbreakfiecho "Number: $i"
done

image-20240511233306914

i等于3时,break语句执行,循环提前结束,因此只会打印1和2。

8.2、多层循环跳出

#!/bin/bash
for ((i=1; i<=3; i++)); dofor ((j=1; j<=3; j++)); doif [ $i -eq 2 ] && [ $j -eq 2 ]; thenbreak 2  # 跳出两层循环fiecho "i=$i, j=$j"done
done

image-20240511233808372

当内层循环的ij都等于2时,使用break 2跳出两层循环,因此不会打印i=2, j=2之后的任何组合。

七、数组

1、索引数组(数值索引)

1.1、定义与赋值

索引数组的元素由整数索引,从0开始

# 定义并初始化数组
myArray=(value1 value2 value3)# 动态追加元素
myArray+=("value4")

1.2、访问元素

echo ${myArray[0]}	#输出第一个元素

image-20240512193414058

1.3、读取数组

echo "数组的元素为: ${myArray[*]}"echo "数组的元素为: ${myArray[@]}"

image-20240512193730834

1.4、获取数组长度

echo "数组的长度为:${#myArray[*]}"echo "数组的长度为:${#myArray[@]}"

image-20240512193852252

1.5、遍历数组

#!/bin/bash
myArray=(A B C D)
myArray+=("E")
echo "读取数组方式一(myArray[@]):"
for i in "${myArray[@]}"; doecho "$i"
done
echo "读取数组方式二(myArray[*]):"
for element in "${myArray[*]}"; doecho "$element"
done

image-20240512194737932

1.6、删除数组元素

1.6.1、删除数组所有元素
#!/bin/bash
myArray=(A B C D)
myArray+=("E")
echo "读取数组方式一(myArray[@]):"
for i in "${myArray[@]}"; doecho "$i"
done
echo "读取数组方式二(myArray[*]):"
for element in "${myArray[*]}"; doecho "$element"
done
echo "unset删除数组中所有元素"
unset myArray
echo ${myArray[@]}
echo ${#myArray[@]}

image-20240512204244136

1.6.2、删除数组中的指定元素
#!/bin/bash# 初始化数组
myArray=(A B C D)# 定义删除元素的函数(函数过会儿讲)
deleteElement() {local index=$1local i=0local newArray=()for element in "${myArray[@]}"; doif [ $i -ne $index ]; thennewArray+=("$element")fi((i++))donemyArray=("${newArray[@]}")
}# 调用函数删除索引为1的元素(记住数组索引从0开始)
deleteElement 1# 打印修改后的数组验证结果
echo "${myArray[@]}"

image-20240512205539322

2、关联数组(字符串索引)

2.1、定义与赋值

#!/bin/bash
#直接赋值
declare -A assocArray1
assocArray1[sorce1]=95
assocArray1[sorce2]=85
assocArray1[sorce3]=75#初始化时赋值
declare -A assocArray2=([sorce1]=100 [sorce2]=90 [sorce3]=80)#追加元素
assocArray1[sorce4]=60

image-20240512214023815

2.2、访问元素

#!/bin/bash
#直接赋值
declare -A assocArray1
assocArray1[sorce1]=95
assocArray1[sorce2]=85
assocArray1[sorce3]=75#初始化时赋值
declare -A assocArray2=([sorce1]=100 [sorce2]=90 [sorce3]=80)#追加元素
assocArray1[sorce4]=60#访问元素
echo "${assocArray1[sorce1]}"
echo "${assocArray2[sorce1]}"

image-20240512214259331

2.3、获取数组长度

#!/bin/bash
#直接赋值
declare -A assocArray1
assocArray1[sorce1]=95
assocArray1[sorce2]=85
assocArray1[sorce3]=75#初始化时赋值
declare -A assocArray2=([sorce1]=100 [sorce2]=90 [sorce3]=80)#追加元素
assocArray1[sorce4]=60#获取数组长度
echo ${#assocArray1[@]}
echo ${#assocArray1[*]}
echo ${#assocArray2[@]}
echo ${#assocArray2[*]}

image-20240512214437910

2.4、遍历函数

#!/bin/bash
# 直接赋值
declare -A assocArray1
assocArray1[sorce1]=95
assocArray1[sorce2]=85
assocArray1[sorce3]=75# 初始化时赋值
declare -A assocArray2=([sorce1]=100 [sorce2]=90 [sorce3]=80)# 追加元素
assocArray1[sorce4]=60# 遍历关联数组1
echo "遍历assocArray1:"
for key in "${!assocArray1[@]}"; doecho "$key: ${assocArray1[$key]}"
done# 遍历关联数组2
echo "遍历assocArray2:"
for key in "${!assocArray2[@]}"; doecho "$key: ${assocArray2[$key]}"
done

image-20240512215219126

2.5、删除数组元素

#!/bin/bash
# 直接赋值
declare -A assocArray1
assocArray1[sorce1]=95
assocArray1[sorce2]=85
assocArray1[sorce3]=75# 初始化时赋值
declare -A assocArray2=([sorce1]=100 [sorce2]=90 [sorce3]=80)# 追加元素
assocArray1[sorce4]=60# 删除数组所有元素
declare -A assocArray1=()# 删除数组指定元素
unset assocArray2[sorce2]# 打印数组1验证(此处应该为空,因为已清空)
echo "打印数组1"
for key1 in "${!assocArray1[@]}"; doecho "成绩: $key1, 值: ${assocArray1[$key1]}"
done# 打印数组2验证
echo "打印数组2"
for key2 in "${!assocArray2[@]}"; doecho "成绩: $key2, 值: ${assocArray2[$key2]}"
done

image-20240512221324957

八、函数

Shell脚本中的函数是组织和复用代码的关键组成部分,允许将一系列命令组合成一个单元,便于多次调用

1、函数的格式

1.1、格式一

function_name() {commands...
}
function_name	#调用函数

1.2、格式二

function function_name {commands...
}
function_name	#调用函数

2、参数传递

函数可以接受任意数量的参数,这些参数在函数体内部可以通过位置参数(如 $1, $2, ...) 访问,$0 通常代表函数名。

#!/bin/bash
greet(){echo "Hello $1!"
}
greet "World"
[root@localhost Shell]# bash greet.sh
Hello World!

image-20240512222901349

3、返回值

函数可以通过return语句返回一个退出状态码,这个状态码通常是一个整数,用来表示函数的执行结果或状态。

在脚本中,可以用 $? 来访问最近的命令或函数的退出状态码。

#!/bin/bash
funWithReturn(){echo "这个函数会对输入的两个数字进行相加运算..."echo "输入第一个数字: "
read aNumecho "输入第二个数字: "
read anotherNumecho "两个数字分别为 $aNum 和 $anotherNum !"return $(($aNum+$anotherNum))
}
funWithReturnecho "输入的两个数字之和为 $? !"
#可以使用$?来获取返回值

image-20240512223905744

九、用户交互(read)

1、基本用法

#!/bin/bash
#读取一行输入并赋值给变量REPLY
read
echo "您输入的是: $REPLY"xxxxxxxxxx read #!/bin/bash#读取一行输入并赋值给变量REPLYreadecho "您输入的是: $REPLY"

image-20240512225111738

2、显示提示信息,等待用户输入(-p)

#!/bin/bash
read -p "请输入你的名字: " nameecho "你好,$name!"

image-20240512225456881

3、限制等待时间(-t)

#!/bin/bash
read -t 5 -p "请在5秒内输入你的年龄: " age
if [ $? -eq 142 ]; thenecho "超时,没有输入。"
elseecho "你的年龄是: $age"
fi

image-20240512225654799

4、启用行编辑功能(-e)

启用行编辑功能。这意味着用户可以使用Backspace键删除输入错误的字符,使用左右箭头键移动光标等。

此选项依赖于终端支持。

read -e -p "请输入信息: " input

5、指定读取的字符数(-n)

限定读取的字符数,而非直到遇见换行符。

#!/bin/bash
read -n 2 -p "请输入两个字符: " twoChars

image-20240512230713031

6、静默模式(-s)

静默模式,不显示用户输入的内容,适用于密码等敏感信息的输入

#!/bin/bash
read -s -p "请输入密码: " password
echo "密码已输入。"

image-20240512231042477

7、指定输出结束的分隔符(-d)

#!/bin/bash
read -d ';' -p "输入多条信息,分号停止: " multiLine

image-20240512231612671

8、数组赋值(<<<)

#!/bin/bash
read -a fruits <<< "apple banana cherry"
echo "${fruits[2]}"  # 输出 "cherry"

image-20240512231854627

十、调试脚本

1、-x进行命令追踪

运行命令: bash -x debug_1.sh

#!/bin/bash
for i in {1..6}
doecho $i
done
echo "Script Executed"

image-20240512233436469

2、-v查看命令和结果

运行命令: bash -v debug_2.sh

#!/bin/bash
#set -v  # 开始详细输出
echo "当前日期是: $(date)"
#set +v  # 结束详细输出

image-20240512233745709

3、-n进行语法检查

#!/bin/bash
for i in {1..6}
do
echo "输出1-6: $i
done

image-20240512234035024

4、-e进行错误处理

#!/bin/bash
set -e  # 遇到错误立即退出
echo "尝试执行一个不存在的命令..."
ld
echo "这行不会被执行,因为上一行命令失败了"

image-20240512234453526

5、查看脚本的退出状态码

  • 0 表示成功;
  • 非零值通常表示某种错误。
#!/bin/bash
cd /debug  # 故意执行一个失败的命令
echo "上一个命令的退出状态码是: $?"

image-20240512235017183

十一、shell脚本实战

挖个坑,回头补

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/30768.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

软件设计师:信息安全

防火墙内网———DMZ隔离区(非军事化区)——外网 通常把Web服务器放在DMZ中 包过滤防火墙(网络层和数据链路层之间)对用户完全透明,速度快 不能防范黑客攻击 应用代理网关防火墙(应用层)彻底隔断内网与外网直接通信 难以配置,处理速度慢 状态检测技术防火墙 目前没考过病毒网…

Scurm冲刺第七天

Scurm冲刺第七天 1. 站立式会议内容昨日已完成任务 今日计划完成任务学习 前后端接口设计与交互实现,前端界面合理跳转功能实现 的相关知识 前后端接口设计与交互实现,前端界面合理跳转功能实现研讨 前端UI设计代码编写(基于用户界面对管理员界面的设计)的解决方法 前端UI设…

CentOS7离线部署JDK

一、 下载JDK 官网地址: https://www.oracle.com/java/technologies/downloads/#java18二、安装部署点击查看代码 ## 创建存放的文件夹 [root@localhost /]# cd / [root@localhost /]# mkdir data [root@localhost /]# cd /data [root@localhost data]# mkdir java## 解压,安…

项目冲刺day5

这个作业属于哪个课程 软工4班这个作业要求在哪里 作业要求1.会议1. 照片2. 昨日已完成: 完成商品管理、图标功能,部分完成文件修改上传功能3.今天计划完成的工作 商品分类,购物车功能。2.燃尽图3.每人的代码签入记录4.适当的项目程序截图5.每日总结 明天继续努力!

Adding Drivers into VMWare ESXi Installation Image

The standard ESXi ISO image doesn’t support most desktop NIC adapters. To install ESXi on such a computer, you will need to inject the drivers for your network adapter into your ESXi installation image Let’s see how to add the driver to the VMware ESXi 6…

如何批量导出地图上商家店铺资料到手机电脑excel表格

搜索打开小程序:小胖汇客。在搜索框中输入商家店铺的关键词。在搜索结果中找到目标商家店铺,在详情页面中,你可以查看商家的地址、电话、营业时间等信息。选中需要下载的商家,一键导出到excel表格

Scrum冲刺6--5.12

Scrum冲刺6--5.12这个作业属于哪个课程 软件工程这个作业要求在哪里 团队项目这个作业的目标 进行敏捷冲刺,熟悉团队合作开发前端仓库 前端后端仓库 后端每次冲刺日志索引时间 博客5.7 Day1ᕙ(`▿)ᕗ5.8 Day2ᕙ(• ॒ ູ•)ᕘ5.9 Day3(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )5.10 Day4 (…

计算机控制apm飞控自动飞行

使用mavproxy(mavlink)控制ArduCopter飞控无人机自动起飞到1米高度然后前进1m然后降落.摘要 使用mavproxy(mavlink)控制ArduCopter飞控无人机自动起飞到1米高度然后前进1m然后降落. 关键信息飞控固件:ArduCopter 4.2.0 飞控MAVProxy 1.8.70 PyMavlink 2.4.41原理简介 mavproxy简…