3. Shell
3. Shell
基本语法
- 注释:
#
- 输出:
echo
- 输入:
read
, 从标准输入读入一个字符串 - 换行:
\
, 一条单一长命令内也可以换行
第一行文件头#!
,标志该文件是 shell 脚本类型。
#!/bin/sh
文件头:文件的前 16 个 bit(前两个字节/英文字符)是 magic number,来说明文件类型,然后用后面的东西解释(sh 可以 ls 也可以,都行,但是能做的内容不一样多)
eg. 0xCAFEBABE 是 Java class 类型
连接命令
在 Linux 中,可以使用以下符号来连接两个命令:
分号
;
: 分号用于分隔两个命令,不考虑前一个命令的执行结果,无论成功与否都会继续执行后续命令。逻辑与
&&
: 逻辑与运算符用于连接两个命令,只有前一个命令成功执行(返回状态码为 0)后,才会执行后续命令。逻辑或
||
: 逻辑或运算符用于连接两个命令,只有前一个命令失败执行(返回状态码非 0)后,才会执行后续命令。
这些符号可以根据需要在 shell 脚本或命令行中使用,以控制命令的执行顺序和条件。
command1; command2 && command3 || command4
command1 \
&& command2 \
&& command3 \
|| command4
执行方法
sh [文件名字]
chmod -x [文件名字]
增加执行权限,然后[文件名字]
source [文件名字]
,将会在当前 shell 中运行 execute 命令. [文件名字]
,将会在当前 shell 中运行 execute 命令,可以接入/修改环境中定义的变量
脚本语言里面,变量基本上不需要声明类型,直接=赋值即可
shell 变量名称喜欢全大写,
- 单引号:单独当作字符串本身,不会进行转义
- 双引号:会进行转义变量或表达式
- 连续的字符可以省略引号,但是如果有括号、空格等符号,则“单引号、双引号、花括号等”无法省略。
变量类型
在 Shell 脚本中,变量的类型是动态的,也就是说,Shell 不需要显式声明变量的类型。以下是在 Shell 中常见的变量类型:
字符串变量: 用于存储文本数据。
name="John"
整数变量: 用于存储整数数据。
age=25
数组变量: 用于存储多个值的列表。
fruits=("apple" "banana" "orange")
关联数组变量: 用于存储键值对的列表。
declare -A person person["name"]="John" person["age"]=25
环境变量: 用于存储系统环境和配置信息。
PATH="/usr/local/bin:/usr/bin:/bin"
只读变量:不允许修改的变量
readonly a="sss"
局部变量:
local
,声明函数等代码块中的局部变量
请注意,Shell 中的变量默认都是字符串类型,包括整数变量。如果需要进行数值计算,Shell 会自动进行类型转换。如果需要显式地将变量解释为整数,可以使用declare
或typeset
命令。
declare -i num=10
此外,还可以使用readonly
关键字将变量声明为只读,以防止其被修改。
readonly name="John"
这些是 Shell 脚本中常见的变量类型。Shell 还支持其他特殊类型,如文件描述符和命令替换等。确保在编写 Shell 脚本时参考相关文档和语法规范。
可选变量
getopts
命令获取和解析命令行选项(options)。解析单个字符的命令行。每个选项使用一个字母表示,后面可以跟一个冒号表示该选项需要一个参数值。
#!/bin/bash
while getopts ":a:b:c" opt; do
case $opt in
a)
echo "Option -a is set with value $OPTARG"
;;
b)
echo "Option -b is set with value $OPTARG"
;;
c)
echo "Option -c is set"
;;
\?)
echo "Invalid option: -$OPTARG"
;;
esac
done
变量引用
就是在变量名前面 + $
符号
$HELLO
${HELLO}
${HELLO:3:4} #引用切片完整版,取3开始的4个字符
${HELLO::4} #开头的4个字符,可以随意缺省部分
${HELLO:3} #3开头往后所有字符
${apps[0]} #apps数组的第0位
${object["name"]} #object关联数组的第name字段
变量引用切片,第一位是起始索引,第二位是保留的位数
字符串操作
$HELLO
${HELLO}
${HELLO:3:4} #引用切片完整版,取3开始的4个字符
${HELLO::4} #开头的4个字符,可以随意缺省部分
${HELLO:3} #3开头往后所有字符
${string^} #首字母大写
${string^^} #全部大写
${string,} #首字母小写
${string,,} #全部小写
${string:start:length}
${#string} #字符串长度
${string/pattern/replacement} #替换第一个匹配项
${string//pattern/replacement} #替换所有匹配项
特殊变量
$# #传入的参数个数
$0 #sh脚本的名
$n #就是输入的第 n 个参数
$@ #所有参数作为独立字符串返回
$* #将所有命令行参数作为单个字符串返回,参数之间使用第一个字符在IFS环境变量中指定的分隔符进行分隔(默认为空格)。
$? #The status of last CMD,上一个命令的返回值(成功是0,失败是1等)
$$ #PID
$! #最后一个在后台运行的进程的PID
${PIPESTATUS[@]} #上一行指令的所有管道的状态
${BASH_SOURCE[0]} #Bash内置的数组,包含了当前正在执行的脚本文件的路径。
字符串(变量值)拼接,直接 echo 后面变量挨着写即可
变量默认值(常用于取不一定设置的环境变量时)
${COLOR:-green} #无的时候用-后面替换
${COLOR:=green} #无的时候用=后面替换,并将这个变量赋值
${#COLOR} #获取COLOR变量的字符串长度
${#COLORS[@]} #获取COLORS数组的长度
${!prefix*} #获取以prefix开头的变量名列表
${!prefix@} #获取以prefix开头的变量名列表
ps 看进程
env 是 set 的子集
export 可以把 set 里面的变量升级为环境变量
环境变量:可以通过父进程传递给子进程的
环境变量是在操作系统中定义的全局变量,可以在整个系统中被访问和使用。它们存储了与系统操作和配置相关的信息,如路径、默认设置和用户首选项等。
在 Shell 脚本中,可以通过以下方式来访问和使用环境变量:
查看环境变量:使用
env
命令可以列出当前系统中定义的所有环境变量。env
或者使用
printenv
命令:printenv
获取环境变量的值:可以使用
$
符号后跟环境变量的名称来获取其值。echo $HOME
上述示例中,
$HOME
表示HOME
环境变量的值。设置环境变量:可以使用
export
命令来设置环境变量。export MY_VARIABLE="Hello World"
上述示例中,
MY_VARIABLE
是新定义的环境变量,其值为Hello World
。通过export
命令,将其设置为全局环境变量,可以在脚本的其他地方访问该变量。取消环境变量:可以使用
unset
命令来取消设置的环境变量。unset MY_VARIABLE
上述示例中,
MY_VARIABLE
环境变量将被取消,并从环境中移除。
环境变量在 Shell 脚本中非常有用,可以用于存储和传递系统配置、用户首选项和其他重要信息。通过合理地使用环境变量,可以提高脚本的灵活性和可配置性。
PATH=.:$PATH #就是加上这个"."#当前目录
恢复的话就是,PATH=${PATH:2}
条件测试
test 条件
[ 条件 ]
测试工具主要就是$?
其实就是在运行一些命令(实际上并不是在变成)
0-255,只用了 8 个 bit
shell 里面 0 是真,其他都是假(与 C 相反)
权限测试
- test -w 文件名,测试他的执行权限
[ -w a.c ]
方括号语法,注意空格一个都不能差,不然报错
字符测试
!=
:=
:=~
: 正则表达式匹配
数字测试
-gt
-lt
-ne
-eq
命令替换
`ls` # 执行命令
$(ls) # 执行命令
<(ls) # 用作将命令的输出作为文本进行处理
loop
for
字符串有空格分割的话,for each
的时候就相当于数组
for variable in list
do
# 执行操作
done
命令行参数扩展:{prefix..suffix}
,如果有多组的话会排列组合,数字可以多位数字,但是字符只能单位字符,否则不解析,字符类会在 ascII 表上的排序。
for i in {1..5}; do
# 执行操作,例如打印数字
echo "$i"
done
for ((i=start; i<=end; i++)); do
# 执行操作,例如打印数字
echo "$i"
done
while & until
while condition
do
# 执行操作
done
counter=1
until [ $counter -gt 5 ]
do
echo $counter
counter=$((counter + 1))
done
执行数学运算$((1+1))
branch
if
if [condition]
then
# code
elif [condition]
then
# code
else [condition]
# code
fi
case
case $opt in
pattern1)
;;
pattern2)
;;
*)
;;
\?)
;;
esac
I/O
echo
read
,读取用户输入的字符
tee
可以把命令的流分成两叉,常用在既把输出到文件又输出他
重定向
输出重定向
>
: 标准输出重定向,覆盖原有内容
>>
: 标准输出追加重定向,将命令的标准输出追加到文件中,如果文件不存在则创建。写在末尾
2>
: 标准错误输出重定向
n>
: 文件描述符输出重定向
$>
, >$
: 标准输出和错误输出合并重定向
m>&n
: 文件描述符合并重定向
输入重定向
<
: 标准输入重定向
<<
: Here Document,通过文档重定向将一块文本作为命令的输入。在 Here Document 中,文本块的起始标记和结束标记必须单独占据一行,并且结束标记必须顶格写。标记的命名可以根据实际情况来选择,但必须保证起始标记和结束标记一致。
n<
: 文件描述符输入重定向
引号
' '只是当做字符串
" "可以转义里面的变量或者公式进行输出
` `命令替换
函数
想要获取输入的参数就用,$1, $2 等
return
返回值,只能是在 0-255 之间的整数,调用者通过$?
获取
字符可以用echo
,调用者通过$(func)
调用并获取结果
include:.
随机数
$RANDOM
: 生成一个介于 0 到 32767 之间的随机整数
cat /dev/urandom | od -N2 -An -i | awk -v f=1 -v r=100 '{printf "%i\n", f + r * $1 / 65536}'
random_number=$(od -An -N2 -i /dev/urandom | awk -v min=1 -v max=10000 '{print min + int(($1 \* (max-min+1)) / 32768)}')
echo "随机数: $random_number"
这条命令的作用是生成一个在给定范围内随机分布的整数。
具体原理如下:
cat /dev/urandom
: /dev/urandom 是 Linux 系统中的一个特殊设备文件,可以读取其内容来获取伪随机数。cat 命令用于将 /dev/urandom 的内容输出到标准输出。
od -N2 -An -i
: od 命令用于将二进制数据转换为不同的格式进行展示。-N2 表示只读取两个字节,-An 表示不输出地址,-i 表示将字节解析为整数。
awk -v f=1 -v r=100 '{printf "%i\n", f + r * $1 / 65536}'
: 这部分利用 awk 命令对输入进行处理。首先,-v f=1 和 -v r=100 分别定义了 awk 的变量 f 和 r,分别表示范围的起始值和区间长度。然后,{printf "%i\n", f + r * $1 / 65536} 用于计算并输出在给定范围内的随机整数。其中,$1 表示 awk 的第一个输入字段,即前一步 od 命令输出的整数,65536 是一个常数,用于将取值范围归一化到 0~1 之间,然后利用乘法和加法操作将其映射到给定的范围内。
综合起来,这条命令的原理是从 /dev/urandom 中读取随机字节,然后通过 od 命令转换为整数,并通过 awk 命令将这些整数映射到给定的范围内,生成随机分布的整数。
set
set 命令可以用来查看当前的 shell 参数设置。它可以显示当前 shell 的各种设置:
- 显示已定义的变量和函数。
- 显示 shell 的设置选项,如:
-e
(如果有语句执行错误,就立即退出)-u
(如果使用未初始化的变量,则报错)
- 显示当前的位置参数。
- 如果在 set 命令后面跟上选项,可以用来修改 shell 的设置。
具体选项如下:
set
: 显示所有已经定义的变量和函数set -o
: 显示当前的 shell 设置(选项)set -e
(或-o errexit
):如果有任何命令执行失败(返回非零状态码),则立即退出 shell。set -u
(或-o nounset
):如果使用未初始化的变量,则报错并退出 shell。set -x
(或-o xtrace
):调试模式,在执行每个命令之前,显示命令的详细输出。set -o pipefail
: 如果管道中的任何命令失败,则整个管道被视为失败。set -n
: 只进行语法检查,而不执行命令。set -f
: 禁用文件名扩展(通配符)。set -v
(或-o verbose
):在执行命令之前显示命令的详细输出。set +H
(或+o histexpand
):禁用命令行历史展开。set +B
(或+o braceexpand
):禁用大括号扩展。set +C
(或+o noclobber
):禁止使用重定向创建已存在的文件。