文章目录
- 1、编写 Shell 脚本文件
- 1_脚本结构
- 2_示例
- 3_执行脚本
- 2、变量的定义与使用
- 1_定义变量
- 2_只读变量
- 3_接受用户输入
- 4_删除变量名
- 5_变量作用域
- 3、字符串处理
- 1_双引号 vs 单引号
- 2_示例
- 4、条件判断&运算符
- 1_数值比较
- 2_case示例
- 3_算数运算符
- 4_逻辑运算符
- 5_字符串运算符
- 6_文件检测运算符
- 5、shell 脚本自带选项
- 6、循环
- 1_for循环
- 2_while循环
- 3_break 和 continue 语句
- 4_select循环
- 7、函数
- 1_函数定义
- 2_使用示例
- 8、数组
- 9、结语
Shell 脚本是用于自动化任务、配置管理和系统管理的重要工具。本文将详细介绍如何编写 Shell 脚本,包括基本语法、变量、条件判断、循环、函数、数组和文件测试等内容。
1、编写 Shell 脚本文件
在 Linux 系统中,可以使用任意文本编辑器(如 vim
、nano
)创建一个 .sh
文件:
# 使用 touch 命令创建一个空文件
touch script.sh # 或者使用 vim 创建并直接打开文件
vim script.sh
在编辑器中输入以下内容(书写规范):
#!/bin/bash
# 下面是 Shell相关命令
echo "Hello, World!"
注意:#!
是一种约定标记, 它可以告诉系统这个脚本需要什么样的解释器来执行;
编写 Shell 脚本主要可以用以下三步来概括:
- 创建
.sh
文件 - 编写
- 执行
在 .sh
文件中,你可以编写各种命令。每个脚本都应以 Shebang 开头,指明解释器。
1_脚本结构
- Shebang:
#!/bin/bash
指定脚本使用的解释器。 - 注释: 以
#
开头的行被视为注释,不会被执行。
2_示例
#!/bin/bash
# 打印当前用户和日期
echo "当前用户: $USER"
echo "当前日期: $(date)"
# 创建一个shellest用户 并创建新文件夹try.html
useradd shelltest
touch /home/shelltest/try.html
# 删除该用户
userdel -r shelltest
3_执行脚本
新创建的脚本可能存在权限问题,使用以下命令执行脚本:
# 使用 bash 解释器执行
bash script.sh # 或添加执行权限并直接执行
chmod +x script.sh # 添加执行权限
./script.sh # 直接执行
2、变量的定义与使用
1_定义变量
在 Shell 中,变量的定义和使用方式如下:
# 定义变量
class_name="shenyang" # 注意:等号两边不能有空格# 使用变量
echo $class_name # 输出:shenyang
注意:在使用时一定要在变量名前加上$
符
第一个脚本程序:
#!/bin/bash
s="hello world"
echo $s
使用脚本定义一个变量输出当前时间,格式“年-月-日 时-分-秒”
#!/bin/bash
dt=`date +'%F %T'`
echo $dt
注意:上述案例中使用了 反引号(esc下方的建),当脚本中需要执行一些指令并将指令执行结果给变量时需要使用反引号``。
不过反引号也可以使用$()
的形式替换掉,示例如下:
#!/bin/bash
dt=$(date +'%F %T')
echo $dt
使用看个人习惯就好。
2_只读变量
在 Shell 编程中,readonly
命令用于将变量或函数设置为只读,防止它们的值被修改或删除。
这在编写脚本时非常有用,能确保关键变量或函数不被意外更改。
语法格式:readonly 变量名
。
#!/bin/bashmy_var="Hello, World!"
readonly my_var# 尝试修改只读变量
my_var="New Value" # 会报错:my_var: readonly variable
3_接受用户输入
语法: read -p 提示信息 变量名
编写一个脚本,要求执行之后提示用户输入文件名称(路径)然后自动为用户创建该文件;
#!/bin/bash
read -p '请输入文件名称(含路径):' filename
touch $filename
echo '创建文件成功'
ls -l $filename
4_删除变量名
语法:unset 变量名
#!/bin/bash
b=20
echo $b
unset b
echo $b
5_变量作用域
- 默认情况下,变量是局部的。
- 使用
export
可以将变量导出为环境变量。
3、字符串处理
Shell 支持双引号和单引号的字符串:
1_双引号 vs 单引号
- 双引号:可以识别变量并支持转义。
- 单引号:原样输出字符串,不识别变量。
2_示例
str1="Hello"
str2='World'
echo "$str1, $str2!" # 输出:Hello, World!
echo '$str1, $str2!' # 输出:$str1, $str2!
4、条件判断&运算符
Shell 提供了 if
语句进行条件判断。基本语法如下:
if [ condition ]; thencommand1
elif [ condition ]; thencommand2
elsecommand3
fi
还有 case
选择语句,用于多条件匹配。
主要用于对多个选择条件进行匹配输出,与if elif
语句结构类似,通常用于脚本传递输入参数,打印出输出结果及内容,其语法格式以case…in
开头,esac
结尾。
case 模式名 in模式 1)命令;;模式 2)命令;;*)不符合以上模式执行的命令esac# 每个模式必须以右括号结束,命令结尾以双分号结束。
1_数值比较
-eq
:等于-ne
:不等于-gt
:大于-lt
:小于-ge
:大于等于-le
:小于等于
示例
#!/bin/bash
read -p "请输入a的值:" a
read -p "请输入b的值:" b
if [ $a -eq $b ]; thenecho 'a等于b'
elif [ $a -ne $b ]; thenecho 'a不等于b'
fi
if [ $a -gt $b ]; thenecho 'a大于b'
elif [ $a -lt $b ]; thenecho 'a小于b'
fi
if [ $a -ge $b ]; thenecho 'a大于或等于b'
elif [ $a -le $b ]; thenecho 'a小于或等于b'
fi
==
用于比较两个数字相同返回true,还有!=
都可以用来进行比较操作。
表达式要放在[]
中间,并且要有空格,例如:[ $a == $b ]
判断相等:
#!/bin/bash
read -p "请输入a的值:" a
read -p "请输入b的值:" b
if [ $a == $b ]; thenecho 'a等于b'
elif [ $a != $b ]; thenecho 'a不等于b'
fi
2_case示例
普通示例:
#!/bin/bash
read -p "请输入一个字符: " char
case $char in
[a-z])echo "小写字母";;
[A-Z])echo "大写字母";;
*)echo "其他字符";;
esac
http服务器启动脚本vim httpd_start.sh
:
#!/bin/bash
# check http server start|stop|status|restart
# by author rivers on 2021-9-27while true; doecho -e "\033[31m start \033[0m\033[32m stop \033[0m \033[33m restart \033[0m\033[34m status \033[0m\033[35m quit \033[0m "read -p "请输入你的选择 start|stop|restart|status|quit: " charcase $char instart)systemctl start httpd && echo "httpd服务已经开启" || echo "开启失败";;stop)systemctl stop httpd && echo "httpd服务已经关闭" || echo "关闭失败";;restart)systemctl restart httpd && echo "httpd服务已经重启" || echo "重启失败";;status)systemctl status httpd && echo -e "\nhttpd 的服务状态已显示\n" || echo "无法获取服务状态";;quit)echo "退出程序"break;;*)echo "无效的选择,请重新输入";;esac
done
3_算数运算符
expr
命令是一款表达式计算工具,使用它完成表达式的求值操作:+ - * / %
。
同理a=20 b=10
,expr $a + $b
(使用反引号包裹) 结果为 30
#!/bin/bash
read -p "请输入a的值:" a
read -p "请输入b的值:" b
val=`expr $a + $b`
cheng=`expr $a \* $b`
echo "两数之和为:$val"
echo "两数之积为:$cheng"
注意:原生bash不支持简单数学运算,但可以通过其他命令实现,如:awk
,expr
4_逻辑运算符
运算符 | 示例 |
---|---|
! 非运算 | [ ! false ] 返回 true |
-o 或运算 | [ $a -lt 20 -o $b -gt 100 ] a=10 b=20 true |
-a 与运算 | [ $a -lt 20 -a $b -gt 100 ] a=10 b=20 false |
示例:
#!/bin/bash# 定义数字变量
a=10
b=20# 示例 1: 非运算 `!`
echo "示例 1: 非运算"
if [ ! $(false) ]; then # 如果不加``shell会将false当做字符串,影响最终结果echo "[ ! false ] 返回 true"
elseecho "[ ! false ] 返回 false"
fi# 示例 2: 或运算 `-o`
echo -e "\n示例 2: 或运算"
a=10
b=20
if [ $a -lt 20 -o $b -gt 100 ]; thenecho "[ \$a -lt 20 -o \$b -gt 100 ] 在 a=10 b=20 时返回 true"
elseecho "[ \$a -lt 20 -o \$b -gt 100 ] 在 a=10 b=20 时返回 false"
fi# 示例 3: 与运算 `-a`
echo -e "\n示例 3: 与运算"
if [ $a -lt 20 -a $b -gt 100 ]; thenecho "[ \$a -lt 20 -a \$b -gt 100 ] 在 a=10 b=20 时返回 true"
elseecho "[ \$a -lt 20 -a \$b -gt 100 ] 在 a=10 b=20 时返回 false"
fi
5_字符串运算符
假设 a='abc' b='efg'
:
运算符 | 作用 | 示例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true | [ $a = $b ] false |
!= | 检测两个字符串是否不相等,不相等返回 true | [ $a != $b ] true |
-z | 检测字符串长度是否为0,为0返回 true | [ -z $a ] false |
-n | 检测字符串长度是否不为0,不为0返回 true | [ -n $a ] true |
str | 检测字符串是否不为空,不为空返回 true | [ $a ] true |
示例:
#!/bin/bash# 定义字符串变量
a="abc"
b="efg"# 示例 1: 等于运算 `=`
echo "示例 1: 等于运算"
if [ "$a" = "$b" ]; thenecho "[ \$a = \$b ] 返回 true"
elseecho "[ \$a = \$b ] 返回 false"
fi# 示例 2: 不等于运算 `!=`
echo -e "\n示例 2: 不等于运算"
if [ "$a" != "$b" ]; thenecho "[ \$a != \$b ] 返回 true"
elseecho "[ \$a != \$b ] 返回 false"
fi# 示例 3: 检测字符串长度是否为0 `-z`
echo -e "\n示例 3: 检测字符串长度是否为0"
if [ -z "$a" ]; thenecho "[ -z \$a ] 返回 true"
elseecho "[ -z \$a ] 返回 false"
fi# 示例 4: 检测字符串长度是否不为0 `-n`
echo -e "\n示例 4: 检测字符串长度是否不为0"
if [ -n "$a" ]; thenecho "[ -n \$a ] 返回 true"
elseecho "[ -n \$a ] 返回 false"
fi# 示例 5: 检测字符串是否不为空
echo -e "\n示例 5: 检测字符串是否不为空"
if [ "$a" ]; thenecho "[ \$a ] 返回 true"
elseecho "[ \$a ] 返回 false"
fi
6_文件检测运算符
常用的为-e
、-f
、-d
:
运算符 | 作用 | 示例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true 。 | [ -b $file ] false |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true 。 | [ -c $file ] false |
-d file | 检测文件是否是目录,如果是,则返回 true 。 | [ -d $file ] false |
-f file | 检测文件是否是普通文件,如果是,则返回 true 。 | [ -f $file ] true |
-g file | 检测文件是否设置了SGID 位,如果是,则返回 true。 | [ -g $file ] false |
-k file | 检测文件是否设置了 粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] false |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] false |
-u file | 检测文件是否设置了SUID 位,如果是,则返回 true。 | [ -u $file ]false |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] true |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] true |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] true |
-s file | 检测文件是否为空,如果是,则返回 true。 | [ -s $file ] true |
-e file | 检测文件是否存在,如果是,则返回 true。 | [ -e $file ] true |
示例:
#!/bin/bash
read -p "请输入文件名称:" filename
if [ -e $filename ]; thenecho '该文件已经存在'
elsetouch $filenameecho '该文件创建成功'
fi
if [ -b $filename ]; thenecho '是块设备'
elseecho '不是块设备'
fi
if [ -c $filename ]; thenecho '是字符设备文件'
elseecho '不是字符设备文件'
fi
if [ -d $file ]; thenecho '是目录'
elseecho '不是目录'
fi
if [ -f $file ]; thenecho '是普通文件'
elseecho '不是普通文件'
fi
if [ -r $file ]; thenecho '可读'
elseecho '不可读'
fi
if [ -w $file ]; thenecho '可写'
elseecho '不可写'
fi
if [ -x $file ]; thenecho '可执行'
elseecho '不可执行'
fi
5、shell 脚本自带选项
自己写的 shell 脚本也能像内置命令一样传递选项、接收参数,接收参数通过 $1
、$2
… 等符号定义。
假设使用如下脚本时传递一些参数:
./script.sh a b c # a b c
在脚本中可以用 $1
表示 a
,$2
表示b
,$0
表示脚本文件自身,去掉则不输出本身:
#!/bin/bash
echo "脚本名: $0"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "第三个参数: $3"
echo $0 $1 $2 $3
案例:创建自定义指令user
可直接执行,user -add 用户名
添加用户 、user -del 用户名
删除用户及其家目录。
1.编写脚本文件user.sh
:
#!/bin/bash
if [ $1 = '-add' ]; thenuseradd $2
elif [ $1 = '-del' ]; thenuserdel -r $2
elseecho '请输入正确命令'
fi
2.再用 vim ~/.bashrc
添加别名
alias user='/home/user/user.sh'
另外,不仅仅是$num
,shell 支持的特殊变量还有很多:
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的第 n 个参数。n 是一个数字,表示第几个参数。例如,第一个参数是 $1 ,第二个参数是 $2 。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
"$*" | 传递给脚本或函数的所有参数,被双引号 (" ) 包含时, 与 $* 的含义不同,下述将详细讲解。 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前 Shell 进程 ID,对于 Shell 脚本,就是这些脚本所运行的进程 ID。 |
6、循环
Shell 脚本支持 for
和 while
循环。
1_for循环
格式:for name [ [ in [ word ... ] ] ; ] do list ; done
for 变量名 in 取值列表; do语句 1
done
示例:
#!/bin/bash
for i in {1..5}; doecho "数字: $i"
done
2_while循环
while
循环语句与for
循环功能类似,主要用于对某个数据域进行循环读取、对文件进行遍历,通常用于需要循环某个文件或者列表,满足循环条件会一直循环,不满足则退出循环,其语法格式以while…do
开头,done
结尾:
while (表达式); do语句1
done
示例
#!/bin/bash
count=1
while [ $count -le 5 ]; doecho "计数: $count"((count++)) # 增加计数
done
打印 1-100 数字:
#!/bin/bash
i=0
while ((i <= 100)); doecho $ii=$(expr $i + 1)
done
与 while
关联的还有一个 until 语句,它与 while
不同之处在于,是当条件表达式为false
时才循环,实际使用中比较少,这里不再讲解。
3_break 和 continue 语句
- break 是终止循环。
- continue 是跳出当前循环。
- break 命令后面还可以跟一个整数,表示跳出第几层循环.
示例 1:在死循环中,满足条件终止循环:
#!/bin/bash
while true; dolet N++if [ $N -eq 5 ]; thenbreakfiecho $N # 输出: 1 2 3 4
done
示例 2:举例子说明 continue 用法
#!/bin/bash
N=0
while [ $N -lt 5 ]; dolet N++if [ $N -eq 3 ]; thencontinuefiecho $N # 输出: 1 2 4 5
done
4_select循环
select 是一个类似于 for 循环的语句
一般用于选择,常用于选择菜单的创建,可以配合PS3来做打印菜单的输出信息,其语法格式以select…in do
开头,done
结尾:
select i in (表达式); do语句
done
select
用于创建菜单,可以简化选择逻辑。
#!/bin/bash
PS3="请选择一个选项: "
select option in "选项1" "选项2" "退出"; docase $option in"选项1")echo "你选择了选项1";;"选项2")echo "你选择了选项2";;"退出")break;;*)echo "无效选项";;esac
done
选择一个mysql版本:
#!/bin/bash
# by author rivers on 2021-9-27
PS3="Select a number: "
while true; doselect mysql_version in 5.1 5.6 quit; docase $mysql_version in5.1)echo "mysql 5.1"break;;5.6)echo "mysql 5.6"break;;quit)exit;;*)echo "Input error, Please enter again!"break;;esacdone
done
7、函数
Shell允许将一组命令集或语句形成一个可用块,这些块称为Shell函数。
Shell函数的用于在于只需定义一次,后期随时使用即可,无需在Shell脚本中添加重复的语句块,其语法格式以function_name(){
开头,以}
结尾。
Shell 函数默认不能将参数传入()
内部,Shell函数参数传递在调用函数名称时传递,例如func_name args1 args2
。
1_函数定义
函数是封装一组命令的机制,可以重复使用。函数的定义方式如下:
function_name() {command1command2
}
调用:
function_name # 直接调用函数名
2_使用示例
Shell 函数很简单,函数名后跟双括号,再跟双大括号。通过函数名直接调用,不加小括号。
#!/bin/bash
greet() {echo "Hello, $1!" # $1 是第一个参数
}greet "Alice" # 输出:Hello, Alice!
注意:函数可以接收多个参数,使用 $1
、$2
等来访问。
#!/bin/bash
func() {VAR=$((1 + 1))return $VARecho "This is a function."
}
func
echo $? # 输出 2
# bash test.sh
8、数组
数组是相同类型的元素按一定顺序排列的集合。
Shell 支持一维数组,使用小括号定义,格式:array=(元素 1 元素 2 元素 3 ...)
:
#!/bin/bash# 定义数组
array=(value1 value2 value3)# 访问数组元素
echo ${array[0]} # 输出:value1
注意:用小括号初始化数组,元素之间用空格分隔。
可以通过下标添加元素:
array[3]="value4" # 添加元素
echo ${array[@]} # 输出所有元素
定义方法 1:初始化数组 array=(a b c)
定义方法 2:新建数组并添加元素 array[下标]=元素
定义方法 3:将命令输出作为数组元素 array=($(command))
9、结语
Shell 脚本是强大的自动化工具,掌握其基本语法和使用方法可以显著提升工作效率。通过不断练习和实际应用,你将能够编写出高效的自动化脚本。
希望这篇博客对你有所帮助!如果你有任何问题或建议,欢迎在下方留言。