文章目录
- 1. 总体认识
- 1.1. Shell概述
- 1.2. 第一个Shell脚本
- 1.3. 注释
- 2. 变量
- 2.1. 定义变量
- 2.2. 使用变量
- 2.3. 只读变量
- 2.4. 删除变量
- 2.5. 变量类型
- 2.5.1. 字符串变量
- 2.5.2. 整数变量
- 2.5.3. 数组变量
- 2.5.4. 环境变量
- 2.5.5. 特殊变量
- 3. 输出
- 3.1. echo命令
- 3.2. printf命令
- 4. 运算符
- 4.1. 运算表达式
- 4.2. 条件表达式
- 4.2.1. 关系运算符
- 4.2.2. 逻辑运算符
- 4.2.3. 字符串运算符
- 4.2.4. 文件测试运算符
- 5. 流程控制
- 5.1. 条件语句
- 5.1.1. if语句
- 5.1.2. case多选择语句
- 5.2. 循环语句
- 5.2.1. for循环
- 5.2.2. while循环
- 5.2.3. 无限循环
- 5.2.4. until循环
- 5.2.5. 跳出循环
- 6. 函数
- 7. 输入输出重定向
- 8. 文件包含
1. 总体认识
1.1. Shell概述
- Shell是一个用C语言编写的程序,这个程序提供了一个界面,用户通过这个界面可以访问操作系统内核的服务。
- Shell既是一种命令语言,又是一种解释型的程序设计语言。
- Shell脚本(shell script),是一种为shell编写的脚本程序。
- Shell编程只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
- Linux的Shell种类众多,常用的有Bourne Shell(/usr/bin/sh或/bin/sh)、Bourne Again Shell(/bin/bash)、C Shell(/usr/bin/csh)、K Shell(/usr/bin/ksh)等等,其中Bourne Again Shell是Bourne Shell的增强版本,兼容性更好,且提供了更多的特性和功能。由于易用和免费,Bash是大多数Linux系统默认的Shell。
1.2. 第一个Shell脚本
- 文件名:test.sh
#!/bin/bash echo "Hello World!"
- shell脚本名:
*.sh
。 - 第一行使用
#!
指定解释器路径。 - 第二行
echo
语句的作用是在终端显示指定内容。
- shell脚本名:
- 运行Shell脚本
- 作为可执行程序
chmod +x ./test.sh # 使脚本具有执行权限 ./test.sh # 执行脚本
- 作为解释器参数
bash test.sh
1.3. 注释
- 单行注释:以
#
开头的行会被解释器忽略。 - 多行注释
:<<EOF
Here文档中的内容不会被执行
EOF: << delimiterdocument
delimiter:'
冒号代表空命令,后面的内容不会执行
'
2. 变量
变量是存储的数据值的名称。
2.1. 定义变量
variable=value
- 注意:变量名和等号之间不能有空格。
- 变量命名要求:
- 只由字母、数字和下划线组成,不能以数字开头。
- 避免使用Shell关键字。
- 习惯上,常量的变量名通常使用大写字母
2.2. 使用变量
variable=value
echo $variable
echo ${variable}
- 变量名外面的花括号是可选的,加花括号是为了帮助解释器识别变量的边界。
- 已定义的变量,可以被重新定义。
variable=value1 echo $variable variable=value2 echo $variable
2.3. 只读变量
variable=value
readonly variable
2.4. 删除变量
variable=value
unset variable
- 变量被删除后不能再次使用。
- unset 命令不能删除只读变量。
2.5. 变量类型
2.5.1. 字符串变量
str1=hello
str2='hello'
str3="hello"
- 变量通常被视为字符串。
- 可以使用单引号 ’ 或双引号 " 来定义字符串
- 单引号字符串的限制
- 单引号字符串里的任何字符都会原样输出,不能进行变量值的替换。
- 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
- 双引号字符串
name="world" str="\"Hello,$name! \"\n" echo -e $str
- 双引号字符串中可以进行值的替换。
- 双引号字符串中可以出现转义字符。
- 使用echo语句显示
\n
要添加参数-e
。
- 拼接字符串
name="world"# 使用双引号
str1="hello, "$name"!"
str2="hello, $name!" # 推荐# 使用单引号
str3='hello, '$name'!'
- 获取字符串的长度
str="hello"
echo ${#str}
echo ${#str[0]}
- 提取子字符串
str="Hello, World!"
echo ${str:1:4} # 输出ello
- 查找子字符串
str="Hello, World"# 获得字符l,o第1次出现时,已经读取的字符串部分
x=${str%%[lo]*} # x的值为He
# x的长度加1即为首次出现指定字符的索引
echo $((${#x}+1)) # 输出3
2.5.2. 整数变量
declare -i intvar=3
typeset -i intvar=3
这样的声明告诉Shell将intvar
视为整数,如果尝试将非整数值赋给它,Shell会尝试将其转换为整数。
2.5.3. 数组变量
- 数组变量可以在一个变量中存储多个值。
- 整数索引数组
array1=(1 2 3 4 5) array2=("1"2"hello" ) array3[0]=value0 array3[2]=value2
- 可以不使用连续的下标,而且下标的范围没有限制。
- 索引数组元素:
${数组名[索引]}
- 获取所有元素:
${数组名[*]}
或${数组名[@]}
,两者的区别是后者常用于迭代。 - 获取数组的长度:
${#数组名[*]}
或${#数组名[@]}
- 获取数组单个元素的长度:
${#数组名[索引]}
- 关联数组
declare -A asarray asarray["name"]="John" asarray["age"]=30declare -A site=(["google"]="www.google.com"["baidu"]="www.baidu.com" )
- 键可以是任意的字符串或者整数
- 键是唯一的
- 使用键访问关联数组元素:
数组名[键]
- 获得所有值:
${数组名[*]}
或${数组名[@]}
,两者的区别是后者常用于迭代。 - 获得所有键:
${!数组名[*]}
或${!数组名[@]}
,两者的区别是后者常用于迭代。 - 获得数组长度:
${#数组名[*]}
或${#数组名[@]}
2.5.4. 环境变量
- 环境变量是由操作系统或用户设置的特殊变量,用于配置Shell的行为和影响其执行环境。
- PATH变量包含了操作系统搜索可执行文件的路径
- 将路径添加PATH
export PATH=${your_path}:$PATH
- 直接在终端执行是临时设置
- 要永久设置则须写入配置文件
- 当前登陆用户配置文件:
~/.bashrc
- 所有用户的配置文件:
/etc/profile
- 写入后要重新加载:
source ${config_path}
- 当前登陆用户配置文件:
- 添加其他环境变量与PATH变量类似
2.5.5. 特殊变量
特殊变量 | 作用 |
---|---|
$0 | 脚本名称 |
$1 , $2 , … | 脚本参数 |
$# | 传递给脚本的参数数量 |
$* | 以一个单字符串接收所有向脚本传递的参数 |
$@ | 以"$1" “ 2 " … " 2" … " 2"…"n” 的形式接收所有参数,常用于迭代 |
$? | 上一个命令的退出状态,0表示没有错误,其他任何值表明有错误。 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
3. 输出
3.1. echo命令
- 命令格式
echo string
- 显示普通字符串
echo "It is a test"
echo It is a test
- 显示转义字符
echo "\"It is a test\""
echo \"It is a test\"
- 显示变量
# 标准输入中读取一行(不允许转义)到变量name
read -r name
echo "$name is good!"
- 显示换行
echo -e "OK! \n" # -e 开启转义
echo "******"
- 显示不换行
echo "OK! \n" # 原样输出\n
echo "******"
echo -e "OK! \c" # -e 开启转义,但不换行
echo "******"
- 原样输出字符串
echo '$name\"'
- 显示命令执行结果
echo "Date: $(date)"
3.2. printf命令
printf
命令模仿C程序库里的printf()
函数。- 命令格式
printf format-string [arguments...]
- 格式化字符串参照C语言
- 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,
format-string
被重用 - 如果没有
arguments
,那么%s
用NULL
代替,%d
用0
代替 - 格式化字符串中的
%b
格式- 用于参数中存在
\n
时,输出换行。用%s
会原样输出\n
。 - 仅在
%b
格式下,\c
可以抑制(不显示)输出结果中任何结尾的换行字符,而且其后的所有内容全部忽略。用%s
会原样输出\c
。
- 用于参数中存在
4. 运算符
4.1. 运算表达式
- 运算表达式的使用
val=$((2 + 2)) echo "$val"
$((...))
中不用考虑空格的问题,变量不用加$
号。- 支持的运算
运算符 含义 举例 +
加法 $((a + b))
-
减法 $((a - b))
*
乘法 $((a * b))
/
除法 $((a / b))
%
取余 $((a % b))
++
自增,与C++相同 $((a++))
--
自减,与C++相同 $((a--))
=
赋值,右值作为结果 $((a = b))
==
比较相等,相等为1,否则为0 $((a - b))
!=
比较不相等,不相等为1,否则为0 $((a - b))
>
比较大于,大于为1,否则为0 $((a - b))
<
比较小于,小于为1,否则为0 $((a - b))
>=
比较大于等于,大于等于为1,否则为0 $((a - b))
<=
比较小于等于,小于等于为1,否则为0 $((a - b))
4.2. 条件表达式
- 条件表达式的使用
a=2 b=1if test $a -eq $b thenecho "相等" elif [ $a -ge $b ] thenecho "大于" elif (($a < $b))echo "小于" elseecho "错误" fi
- 条件表达式通常用于流程控制中
- 条件判断可以使用
test 条件表达式
- 条件判断可以使用
[ 条件表达式 ]
,注意要有空格 - 条件判断可以使用
((条件表达式))
,此时可以不用考虑空格
4.2.1. 关系运算符
只支持数字,不支持字符串。
运算符 | 含义 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返true。 | [ $a -eq $b ] |
-ne | 检测两个数是否不相等,不相等返回true。 | [ $a -ne $b ] |
-gt | 检测两个数是否大于右边的,如果是,则返回true。 | [ $a -gt$b ] |
-lt | 检测两个数是否小于右边的,如果是,则返回true。 | [ $a -lt $b ] |
-ge | 检测两个数是否大于等于右边的,如果是,则返回true。 | [ $a -ge $b ] |
-le | 检测两个数是否小于等于右边的,如果是,则返回true。 | [ $a -le $b ] |
4.2.2. 逻辑运算符
优先级:! > && > ||
,存在短路运算。
运算符 | 含义 | 举例 |
---|---|---|
&& | 逻辑与运算 | [[ $a -lt 100 && $b -gt 15 ]] |
|| | 逻辑或运算 | [[ $a -lt 100 || $b -gt 15 ]] |
! | 逻辑非运算 | [[ ! $a -lt 100 ]] |
4.2.3. 字符串运算符
运算符 | 含义 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [ $a != $b ] |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] |
-n | 检测字符串长度是否不为0,不为0返回 true。 | [ -n $a ] |
$ | 检测字符串是否不为空,不为空返回 true。 | [ $a ] |
4.2.4. 文件测试运算符
用于检测Unix文件的各种属性。
运算符 | 含义 | 举例 |
---|---|---|
-b | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] |
-c | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] |
-d | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] |
-f | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] |
-g | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] |
-k | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] |
-p | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] |
-u | 检测文件是否设置了SUID位,如果是,则返回 true。 | [ -u $file ] |
-r | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] |
-w | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] |
-x | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] |
-s | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] |
-e | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] |
-S | 判断某文件是否 socket。 | [ -S $file ] |
-L | 检测文件是否存在并且是一个符号链接。 | [ -L $file ] |
5. 流程控制
5.1. 条件语句
5.1.1. if语句
- 最展开的格式
if 条件判断
then命令1命令2...
elif 条件判断
then命令1命令2...
else命令1命令2...
fi
- 写成一行要加分号分隔
if 条件判断; then 命令; fi
if 条件判断; then命令1命令2...
fi
5.1.2. case多选择语句
case 值 in
模式1)command1command2...commandN;;
模式2)command1command2...commandN;;*)command1command2...commandN;;
esac
5.2. 循环语句
5.2.1. for循环
- 最展开的格式
for var in item1 item2
do命令1命令2...
done
- 写成一行要加分号分隔
for var in item1 item2; do 命令1; 命令2; done
5.2.2. while循环
- 一般格式
while 条件判断
do命令1命令2...
done
- 循环读取键盘输入
while read -r site
doecho "是的!$site 是一个好网站"
done
5.2.3. 无限循环
while true
do命令
done
5.2.4. until循环
先执行,再判断
until 条件判断
do命令
done
5.2.5. 跳出循环
break
是跳出本级循环continue
跳出本次循环
6. 函数
- 格式
function funname [()]
{action[return int;]
}[ function ] funname ()
{action[return int;]
}
- 所有函数在使用前必须定义。
- 调用函数仅使用其函数名即可。
- 返回值
- 如果不return语句,将以最后一条命令运行结果作为返回值。
- 只能返回0-255。
- 函数返回值在调用该函数后通过
$?
来获得。
- 函数参数与脚本的命令行参数相同
7. 输入输出重定向
- 文件描述符
- 0表示标准输入(STDIN)
- 1表示标准输出(STDOUT)
- 2表示标准错误输出(STDERR)
- 空设备文件nul(指向/dev/null)
- 输出重定向到文件,覆盖原文件。
command > file
- 输出以追加的方式重定向到文件
command >> file
- 合并标准输出和标准错误输出,并重定向到文件
command > file 2>&1
- 错误输出重定向到文件
command 2> file
- 将输入重定向为文件
command < file
- Here文档:将输入重定向为两个分隔符之间的内容
command << delimiterdocument delimiter
- 对标准输入和标准输出都进行重定向
command < file1 > file2
- 屏蔽命令输出
command > nul command > /dev/null
8. 文件包含
. filename # 注意有空格
source filename
上述语句会先执行指定shell脚本,但是保留shell脚本执行结束会清理的变量等内容