shell脚本编程
一、什么是shell
1、简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。 Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
简单来说,Shell就是用户与操作系统之间的命令解释器
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
2、通过进程信息查看
ps | grep $$ | awk '{print $4}'
3、/etc/passwd
文件查看
grep ^$(whoami) /etc/passwd | awk -F "/" '{print $4}'
二、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
验证了等号两侧不能有空格
2.3、赋值时使用的符号
2.3.1、使用双引号""
[root@localhost ~]# name=misaki
[root@localhost ~]# TEXT="hello $name"
[root@localhost ~]# echo $TEXT
hello misaki
2.3.2、使用单引号''
[root@localhost ~]# test='ls -1'
[root@localhost ~]# echo $test
ls -1
2.3.3、使用反引号``
[root@localhost ~]# test=`ls -1`
[root@localhost ~]# echo $test
anaconda-ks.cfg
2.3.4、使用$()
[root@localhost ~]# test=$(ls -1)
[root@localhost ~]# echo $test
anaconda-ks.cfg
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
2.5、撤销变量的值
格式:unset 变量
[root@localhost ~]# unset user_name
[root@localhost ~]# echo $user_name
2.6、静态变量
格式:readnoly 变量
静态变量不能unset(撤销)
[root@localhost ~]# readonly n1=1
[root@localhost ~]# echo $n1
1
[root@localhost ~]# unset n1
-bash: unset: n1: 无法反设定: 只读 variable
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
最开始在父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" ]; then
echo "The file exists."
fi
1.2、双分支结构
if [ 条件表达式 ]; then
条件为真时执行的命令
else
条件为假时执行的命令
fi
1.2.1、示例:判断数字奇偶
#!/bin/bash
read -p "输入一个数字:" num
if [ $((num % 2)) -eq 0 ]; then
echo "输入的数字是偶数"
else
echo "输入的数字是奇数"
fi
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 ]; then
echo "Grade: A"
elif [ "$sorce" -ge 80 ]; then
echo "Grade: B"
elif [ "$sorce" -ge 70 ]; then
echo "Grade: C"
elif [ "$sorce" -ge 60 ]; then
echo "Grade: D"
else
echo "Grade: F"
fi
2、for循环语句
2.1. 列表遍历形式
for 变量名 in 列表
do
命令序列
done
- 变量名:在每次循环中用来存储当前遍历到的值。
- 列表:可以是逗号分隔的值列表、文件名通配符(如
*
)、命令的输出(用反引号...
或$(...)
包裹),或是任何能产生多个项目的序列。
2.1.1、示例:遍历数字列表、文件、命令
#!/bin/bash
#遍历数字列表
for i in 1 2 3 4 5
do
echo $i
done
#遍历文件
for file in *.sh
do
echo "Processing file: $file"
done
#遍历命令输出
for ip in $(hostname -I)
do
echo "IP address: $ip"
done
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)
do
echo $i
done
#使用brace expansion
echo for_brace expansion
for n in {1..5}
do
echo $n
done
2.3、 C风格的for循环
for (( 表达式1; 表达式2; 表达式3 ))
do
命令序列
done
- 表达式1:初始化部分,通常用于设置循环变量的初始值。
- 表达式2:条件表达式,当其值为真(非零)时继续循环。
- 表达式3:更新部分,每次循环后执行,常用于改变循环变量的值。
2.3.1、示例:生成序列
#!/bin/bash
for (( i=1;i<5;i++ ))
do
echo $i
done
[root@localhost Shell]# bash for_3.sh
1
2
3
4
3、while循环语句
3.1、标准格式
while [条件表达式 ];
do
命令序列
done
- 条件表达式:一个命令或表达式,其退出状态决定循环是否继续。如果表达式的退出状态为0(真),则循环继续;否则,循环终止。
- 命令序列:在每次循环中执行的命令集合。这些命令可以是一条或多条语句,通常用于改变循环控制变量的值,以确保循环最终能够结束,防止死循环。
3.1.1、示例:基础计数循环
#!/bin/bash
i=1
while [ $i -le 5 ]
do
echo "This is loop number $i"
i=$((i+1)) # 或 ((i++))
done
3.2、结合read逐行处理文件
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
从标准输入读取文件中的每一行,并将其赋值给变量
line
3.2.1、示例:读文件行
#!/bin/bash
count=0
while IFS= read -r line
do
let count+=1
echo " Line$count: $line"
done < /etc/passwd
4、until循环语句
until
循环会重复执行一系列命令,直到给定的条件变为真(即条件表达式的退出状态为0。确保
until
循环中的条件最终能够变为真,以避免创建无限循环。
until [条件表达式]
do
命令序列
done
4.1示例:计数到5
#!/bin/bash
i=0
until [ $i -ge 5 ]
do
echo "Counter: $i"
i=$((i+1))
done
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 列表; do
case $变量名 in
选项1)
相应的命令序列
;;
选项2)
其他命令序列
;;
*)
默认或无效选项处理
;;
esac
done
6.1、示例:星期几
#!/bin/bash
day_of_week=$(date +%u) # %u 返回1(星期一) 到7(星期日)
# 通过case语句匹配今天的星期并输出对应信息
case $day_of_week in
1)
echo "今天是星期一,一周的开始,努力工作!"
;;
2)
echo "星期二,继续加油!"
;;
3)
echo "过了星期三,翻过一座山,星期三愉快!"
;;
4)
echo "星期四,期待周末的到来!"
;;
5)
echo "星期五,马上就是周末啦,坚持一下!"
;;
6|7) # 星期六和星期日一起处理
echo "周末啦,好好休息,享受生活!"
;;
*)
echo "无法识别的日期格式,请检查date命令是否正常工作。"
;;
esac
# 脚本执行完case语句后自动退出
exit 0
7、continue语句
continue
语句是一个流程控制命令,用于跳过当前循环迭代中剩余的部分命令,直接开始下一次循环迭代(如果条件仍允许循环继续的话)
7.1、示例
假设我们有一个脚本,想要打印1到10之间的数字,但跳过偶数:
#!/bin/bash
for i in {1..10}; do
if [ $((i % 2)) -eq 0 ]; then
continue
fi
echo $i
done
7.2、注意事项
- 作用范围:
continue
只影响最直接包围它的循环。如果在嵌套循环中使用continue
,它只会跳过当前层次循环的剩余部分,不会影响外层循环。 - 与break的区别:
break
语句会立即终止整个循环,而不仅仅是当前迭代,直接跳出循环体。 - 使用场景:
continue
常用于在满足特定条件时略过循环体中某些不必要的操作,而继续执行后续的迭代,这对于过滤或跳过某些循环过程中的情况非常有用。
8、break语句
break
语句是一个流程控制命令,用于提前退出循环结构,包括for
、while
、until
循环以及select
语句。
8.1、单层循环跳出
#!/bin/bash
for i in {1..5}; do
if [ $i -eq 3 ]; then
break
fi
echo "Number: $i"
done
当
i
等于3时,break
语句执行,循环提前结束,因此只会打印1和2。
8.2、多层循环跳出
#!/bin/bash
for ((i=1; i<=3; i++)); do
for ((j=1; j<=3; j++)); do
if [ $i -eq 2 ] && [ $j -eq 2 ]; then
break 2 # 跳出两层循环
fi
echo "i=$i, j=$j"
done
done
当内层循环的
i
和j
都等于2时,使用break 2
跳出两层循环,因此不会打印i=2, j=2
之后的任何组合。
七、数组
1、索引数组(数值索引)
1.1、定义与赋值
索引数组的元素由整数索引,从0开始
# 定义并初始化数组
myArray=(value1 value2 value3)
# 动态追加元素
myArray+=("value4")
1.2、访问元素
echo ${myArray[0]} #输出第一个元素
1.3、读取数组
echo "数组的元素为: ${myArray[*]}"
echo "数组的元素为: ${myArray[@]}"
1.4、获取数组长度
echo "数组的长度为:${#myArray[*]}"
echo "数组的长度为:${#myArray[@]}"
1.5、遍历数组
#!/bin/bash
myArray=(A B C D)
myArray+=("E")
echo "读取数组方式一(myArray[@]):"
for i in "${myArray[@]}"; do
echo "$i"
done
echo "读取数组方式二(myArray[*]):"
for element in "${myArray[*]}"; do
echo "$element"
done
1.6、删除数组元素
1.6.1、删除数组所有元素
#!/bin/bash
myArray=(A B C D)
myArray+=("E")
echo "读取数组方式一(myArray[@]):"
for i in "${myArray[@]}"; do
echo "$i"
done
echo "读取数组方式二(myArray[*]):"
for element in "${myArray[*]}"; do
echo "$element"
done
echo "unset删除数组中所有元素"
unset myArray
echo ${myArray[@]}
echo ${#myArray[@]}
1.6.2、删除数组中的指定元素
#!/bin/bash
# 初始化数组
myArray=(A B C D)
# 定义删除元素的函数(函数过会儿讲)
deleteElement() {
local index=$1
local i=0
local newArray=()
for element in "${myArray[@]}"; do
if [ $i -ne $index ]; then
newArray+=("$element")
fi
((i++))
done
myArray=("${newArray[@]}")
}
# 调用函数删除索引为1的元素(记住数组索引从0开始)
deleteElement 1
# 打印修改后的数组验证结果
echo "${myArray[@]}"
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
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]}"
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[*]}
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[@]}"; do
echo "$key: ${assocArray1[$key]}"
done
# 遍历关联数组2
echo "遍历assocArray2:"
for key in "${!assocArray2[@]}"; do
echo "$key: ${assocArray2[$key]}"
done
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[@]}"; do
echo "成绩: $key1, 值: ${assocArray1[$key1]}"
done
# 打印数组2验证
echo "打印数组2"
for key2 in "${!assocArray2[@]}"; do
echo "成绩: $key2, 值: ${assocArray2[$key2]}"
done
八、函数
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!
3、返回值
函数可以通过
return
语句返回一个退出状态码,这个状态码通常是一个整数,用来表示函数的执行结果或状态。在脚本中,可以用
$?
来访问最近的命令或函数的退出状态码。
#!/bin/bash
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
#可以使用$?来获取返回值
九、用户交互(read)
1、基本用法
#!/bin/bash
#读取一行输入并赋值给变量REPLY
read
echo "您输入的是: $REPLY"xxxxxxxxxx read #!/bin/bash#读取一行输入并赋值给变量REPLYreadecho "您输入的是: $REPLY"
2、显示提示信息,等待用户输入(-p)
#!/bin/bash
read -p "请输入你的名字: " name
echo "你好,$name!"
3、限制等待时间(-t)
#!/bin/bash
read -t 5 -p "请在5秒内输入你的年龄: " age
if [ $? -eq 142 ]; then
echo "超时,没有输入。"
else
echo "你的年龄是: $age"
fi
4、启用行编辑功能(-e)
启用行编辑功能。这意味着用户可以使用Backspace键删除输入错误的字符,使用左右箭头键移动光标等。
此选项依赖于终端支持。
read -e -p "请输入信息: " input
5、指定读取的字符数(-n)
限定读取的字符数,而非直到遇见换行符。
#!/bin/bash
read -n 2 -p "请输入两个字符: " twoChars
6、静默模式(-s)
静默模式,不显示用户输入的内容,适用于密码等敏感信息的输入
#!/bin/bash
read -s -p "请输入密码: " password
echo "密码已输入。"
7、指定输出结束的分隔符(-d)
#!/bin/bash
read -d ';' -p "输入多条信息,分号停止: " multiLine
8、数组赋值(<<<)
#!/bin/bash
read -a fruits <<< "apple banana cherry"
echo "${fruits[2]}" # 输出 "cherry"
十、调试脚本
1、-x
进行命令追踪
运行命令:
bash -x debug_1.sh
#!/bin/bash
for i in {1..6}
do
echo $i
done
echo "Script Executed"
2、-v
查看命令和结果
运行命令:
bash -v debug_2.sh
#!/bin/bash
#set -v # 开始详细输出
echo "当前日期是: $(date)"
#set +v # 结束详细输出
3、-n
进行语法检查
#!/bin/bash
for i in {1..6}
do
echo "输出1-6: $i
done
4、-e
进行错误处理
#!/bin/bash
set -e # 遇到错误立即退出
echo "尝试执行一个不存在的命令..."
ld
echo "这行不会被执行,因为上一行命令失败了"
5、查看脚本的退出状态码
- 0 表示成功;
- 非零值通常表示某种错误。
#!/bin/bash
cd /debug # 故意执行一个失败的命令
echo "上一个命令的退出状态码是: $?"
十一、shell脚本实战
挖个坑,回头补
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)