Shell学习笔记
# Shell 脚本
Shell 脚本的第一行一般是:
#!/bin/bash
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 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)
- Shell for Root(/sbin/sh)
- ……
# 运行 Shell 脚本的两种方法
# 作为可执行程序
chmod +x ./test.sh # 使脚本具有执行权限
./test.sh # 执行脚本
2
注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。
# 作为解释器参数
/bin/sh ./test.sh # 执行脚本
sh ./test.sh # 执行脚本
2
# Shell 脚本名称及路径操作
变量 | 作用 |
---|---|
$(basename $0) | 获取当前正在执行的脚本名称 |
$(cd $(dirname $0); pwd) | 获取当前正在执行的脚本的父目录的绝对路径 |
# pwd
Linux pwd(英文全拼:print work directory) 命令用于显示工作目录。
执行 pwd 指令可立刻得知您目前所在的工作目录的绝对路径名称。
# basename
basename 用于获取文件路径中的文件名部分。
basename 命令的语法如下:
basename NAME [SUFFIX]
basename OPTION... NAME...
2
其中,OPTION 是可选的参数,NAME 是要处理的文件名或路径。
basename 命令会将 NAME 中的路径部分去除,只保留文件名部分,并将结果输出。
以下是一些常用的 basename 命令的示例:
# 输出结果为file.txt,去除了路径部分
basename /path/to/file.txt
# 输出结果为directory,去除了路径部分,并且保留了末尾的斜杠
basename /path/to/directory/
# 输出结果为file,去除了路径部分,并且去除了指定的文件扩展名
basename /path/to/file.txt .txt
2
3
4
5
6
7
8
# dirname
dirname 用于获取指定路径的父目录,返回指定路径中最后一个斜杠(/)之前的部分。当指定的路径不存在父目录时,dirname命令会返回根目录(/)
# Shell 变量
https://www.runoob.com/linux/linux-shell-passing-arguments.html (opens new window)
Shell 变量名只能包含字母、数字和下划线,不能以数字开头。
变量名与等号之间不能有空格。等号两侧避免使用空格:
# 正确的赋值
variable_name=value
# 有可能会导致错误
variable_name = value
2
3
4
5
使用一个定义过的变量,只要在变量名前面加美元符号即可,如:
echo $variable_name
echo ${variable_name}
2
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界。推荐给所有变量加上花括号,避免不必要的错误,如:
for skill in Java Python Shell; do
# 解释器会把$skillScript当成一个变量(其值为空)
echo "I am good at $skillScript"
echo "I am good at ${skill}Script"
done
2
3
4
5
已定义的变量,可以被重新定义,如:
variable_name=new_value # 使用变量的时候才加美元符($)
# 字符串变量
字符串变量:使用单引号 ' 或双引号 " 来定义字符串,例如:
my_string='Hello, World!'
或者
my_string="Hello, World!"
2
3
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的。
双引号里可以有变量,可以出现转义字符。
拼接字符串:
your_name="runoob"
# 使用双引号拼接
greeting_1="hello, "$your_name" !"
greeting_2="hello, ${your_name} !"
echo $greeting_1 $greeting_2
# 使用单引号拼接
greeting_3='hello, '$your_name' !'
greeting_4='hello, ${your_name} !' # 原样输出hello, ${your_name} !
echo $greeting_3 $greeting_4
2
3
4
5
6
7
8
9
10
获取字符串长度:
string="abcd"
echo ${#string} # 等价于 ${#string[0]}
2
# 整数变量
整数变量: 在一些Shell中,你可以使用 declare 或 typeset 命令来声明整数变量。
declare -i my_integer=42
# 数组变量
数组变量: Shell 也支持数组,允许你在一个变量中存储多个值。
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
数组名=(值1 值2 ... 值n)
例如:
array_name=(value0 value1 value2 value3)
或者:
array_name=(
value0
value1
value2
value3
)
2
3
4
5
6
整数索引数组:
my_array=(1 2 3 4 5)
Bash 支持关联数组,可以使用任意的字符串、或者整数作为下标来访问数组元素。
关联数组使用 declare 命令来声明,语法格式如下:
declare -A array_name
-A 选项就是用于声明一个关联数组。
关联数组的键是唯一的。
declare -A associative_array
associative_array["name"]="John"
associative_array["age"]=30
2
3
读取数组元素值的一般格式是:
${数组名[下标]}
例如:
valuen=${array_name[n]}
数组常用脚本:
array_name[0]=A
array_name[1]=B
array_name[2]=C
array_name[3]=D
# 获取数组中的所有元素
echo "数组的元素为: ${array_name[*]}"
echo "数组的元素为: ${array_name[@]}"
# 在数组前加一个感叹号 ! 可以获取数组的所有键,例如:
echo "数组的键为: ${!array_name[*]}"
echo "数组的键为: ${!array_name[@]}"
# 取得数组元素的个数
echo "数组元素的个数为: ${#array_name[*]}"
echo "数组元素的个数为: ${#array_name[@]}"
# 取得数组单个元素的长度
echo "第n个数组元素的长度为: ${#array_name[n]}"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 环境变量
环境变量: 这些是由操作系统或用户设置的特殊变量,用于配置 Shell 的行为和影响其执行环境。
例如,PATH 变量包含了操作系统搜索可执行文件的路径:
echo $PATH
# 特殊变量
特殊变量: 有一些特殊变量在 Shell 中具有特殊含义。例如:
特殊变量 | 说明 |
---|---|
$0 | 脚本或函数的名称 $0 为脚本执行时传入的脚本路径名,一般在shell中执行文件都用绝对路径 |
$1...$2 | $1 表示脚本或函数的第一个参数,$2 表示脚本或函数的第二个参数,当n>=10时,需要使用${n}来获取参数。。 |
$# | 传递到脚本或函数的参数个数 |
$* | 传递给脚本或函数的全部参数。以一个单字符串显示所有传递到脚本或函数的参数 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 传递给脚本或函数的全部参数。 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。在Linux shell脚本中,可以使用特殊变量$?来获取上一个命令的退出状态码(exit status code)。这个状态码是上一个命令执行后退出的时候返回的数值。一般来说,如果命令执行成功,状态码为0;如果命令执行失败,状态码非0。退出状态码是一个0到255的整数。一般来说,正数的退出状态码是由程序自己定义的,通常用于表示不同的错误类型。而负数的退出状态码通常是由于shell内部错误或者是信号导致的。在实际应用中,你应该尽量避免返回负的退出状态码,除非这是由于shell内部的特定错误。如果你的程序需要返回错误代码,应当使用0以上的正数值。 |
退出码 | 解释 |
---|---|
0 | 命令成功执行 |
1 | 通用错误代码 |
2 | 命令(或参数)使用不当 |
126 | 权限被拒绝(或)无法执行 |
127 | 未找到命令,或 PATH 错误 |
128+n | 命令被信号从外部终止,或遇到致命错误 |
130 | 通过 Ctrl+C 或 SIGINT 终止(终止代码 2 或键盘中断) |
143 | 通过 SIGTERM 终止(默认终止) |
255/* | 退出码超过了 0-255 的范围,因此重新计算(LCTT 译注:超过 255 后,用退出码对 256 取模) |
Exit Code Number | Meaning | Example | Comments |
---|---|---|---|
1 | Catchall for general errors | var1 = 1/0 | Miscellaneous errors, such as "divide by zero" and other impermissible operations |
126 | Command invoked cannot execute | /dev/null | Permission problem or command is not an executable |
127 | "command not found" | illegal_command | Possible problem with $PATH or a typo |
128 | Invalid argument to exit | exit 3.14159 | exit takes only integer args in the range 0 - 255 (see first footnote) |
128+n | Fatal error signal "n" | kill -9 $PPID of script | $? returns 137 (128 + 9) |
130 | Script terminated by Control-C | Ctl-C | Control-C is fatal error signal 2, (130 = 128 + 2, see above) |
255* | Exit status out of range | exit -1 | exit takes only integer args in the range 0 - 255 |
以下是一个简单的示例脚本,它检查最后一个命令的退出状态码,并打印出相应的消息:
#!/bin/bash
# 执行一个命令
ls /some/directory
# 检查命令的退出状态码
if [ $? -eq 0 ]; then
echo "命令执行成功"
else
echo "命令执行失败,退出状态码为 $?"
fi
2
3
4
5
6
7
8
9
10
11
在实际使用中,通常会直接在命令后面进行检查,而不是先执行命令,再检查$?
:
#!/bin/bash
# 直接在命令后检查状态码
if ls /some/directory; then
echo "命令执行成功"
else
echo "命令执行失败,退出状态码为 $?"
fi
2
3
4
5
6
7
8
知识扩展——return和exit的使用:
- return是一个关键字; exit是一个函数。
- return是编程语言级别,它表示调用堆栈的返回;exit是系统调用级别,它表示了一个进程的结束。
- return是函数的退出(返回);exit是进程的退出,exit用于退出整个shell脚本进程。
# 局部变量
local一般用于局部变量声明,多在在函数内部使用。
(1)shell脚本中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止。
(2)shell函数定义的变量默认是global的,其作用域从“函数被调用时执行变量定义的地方”开始,到shell结束或被显示删除处为止。函数定义的变量可以被显示定义成local的,其作用域局限于函数内。但请注意,函数的参数是local的。
(3)如果同名,Shell函数定义的local变量会屏蔽脚本定义的global变量。
# 高级变量
在bash shell中,$算符会触发3种扩展。基本形式如下表:
基本型 | 扩展种类 | 范例 |
---|---|---|
${变量名称} | 变量扩展 | ${filename} |
$(命令) | 命令扩展 | $(ls /) |
$((算术式)) | 算术扩展 | $((9+9)) |
# 变量扩展
在Shell中,变量扩展修饰符用于指定如何扩展变量。这些修饰符可以与参数替换一起使用,以实现特定的扩展行为。
语法 | 说明 |
---|---|
${待测变量-默认值} | 条件判断。测试空值。若变量不存在,返回默认值。 |
${待测变量:-默认值} | 条件判断。测不存在。若变量不存在或为空,返回默认值。 |
${待测变量:=默认值} | 条件判断。设默认值。若变量不存在或为空,给变量设置一个默认值并返回。 |
${待测变量:?提示信息} | 条件判断。检查问题。若变量不存在或为空,则打印提示信息并退出。 |
${待测变量:+真值} | 条件判断。测试存在。若变量存在且其值非空,返回变量的值。 |
${#变量} | 字符串长度。计算字符串长度。 |
${#数组[@]} ${#数组[*]} | 数组长度。取得数组元素个数。 |
${变量:位置起点} | 字符串切片。由指定位置开始,截取子字符串到字符串结束。 |
${变量:位置起点:长度} | 字符串切片。由指定位置开始,截取指定长度的子字符串。 |
${变量#样式} | 最短匹配删除。由最左边(前面)开始,对比变量值,删除最短相符的字符串。 filename=/path/to/file echo ${filename#/*/} 打印 to/file |
${变量##样式} | 最长匹配删除。由最左边(前面)开始,对比变量值,删除最长相符的字符串。 filename=/path/to/file echo ${filename##/*/} 打印 file |
${变量%样式} | 最短匹配删除。由最右边(后面)开始,对比变量值,删除最短相符的字符串。 filename=/path/to/file echo ${filename%/*} 打印 /path/to |
${变量%%样式} | 最长匹配删除。由最右边(后面)开始,对比变量值,删除最长相符的字符串。 filename=/path/to/file echo ${filename%%/*} 空白 |
${变量/样式/替换字符串} | 取代字符串。只替换第一个对比符合的字符串。若变量中,有符合样式的字符串(取最长的),则使用替换字符串予以取代。 |
${变量//样式/替换字符串} | 取代字符串。替换全部对比符合的字符串。若变量中,有符合样式的字符串(取最长的),则使用替换字符串全部予以替换。 |
${变量/样式/} | 删除字符串。只删除一个。删除第一个符合样式的字符串。 |
${变量//样式/} | 删除字符串。删除全部。删除所有符合样式的字符串。 |
# Shell 基本运算符
https://www.runoob.com/linux/linux-shell-basic-operators.html (opens new window)
# 算数运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
#!/bin/bash
val=`expr 2 + 2`
echo "两数之和为 : $val"
2
3
4
两点注意:
- 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。
- 完整的表达式要被 `` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。
# 自增和自减操作符
使用 $(( )) 进行算术运算
#!/bin/bash
# 初始化变量
num=5
# 自增
num=$((num + 1))
# 自减
num=$((num - 1))
echo $num
2
3
4
5
6
7
8
9
10
11
12
# 关系运算符(数值)
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
如果使用 ((...))
作为判断语句,大于和小于可以直接使用 > 和 <,其他如此类推。
运算符 | 说明 | 举例 |
---|---|---|
== | 检测两个数是否相等,相等返回 true。 | (( $a == $b )) 返回 false。 |
!= | 检测两个数是否不相等,不相等返回 true。 | (( $a != $b )) 返回 true。 |
> | 检测左边的数是否大于右边的,如果是,则返回 true。 | (( $a > $b )) 返回 false。 |
< | 检测左边的数是否小于右边的,如果是,则返回 true。 | (( $a < $b )) 返回 true。 |
>= | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | (( $a >= $b )) 返回 false。 |
<= | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | (( $a <= $b )) 返回 true。 |
# 字符串运算符
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [[ $a = $b ]] 返回 false。 |
!= | 检测两个字符串是否不相等,不相等返回 true。 | [[ $a != $b ]] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [[ -z $a ]] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [[ -n "$a" ]] 返回 true。 |
$ | 检测字符串是否不为空,不为空返回 true。 | [[ $a ]] 返回 true。 |
# 文件测试运算符
操作符 | 说明 | 举例 |
---|---|---|
-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 | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
-S file | 判断某文件是否 socket。 | |
-L file | 检测文件是否存在并且是一个符号链接。 |
# 布尔运算符
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
# 逻辑运算符
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 || $b -gt 100 ]] 返回 true |
# Shell test 命令
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。
在Shell脚本中,test
命令和[]
(方括号表达式)都用于条件测试,但它们在使用上有一些区别。
- test命令:这是一个独立的命令,用于测试条件表达式的值,并根据测试结果返回0(真)或非0值(假)。例如,
test -f file.txt
会检查file.txt
是否存在并且是一个普通文件。如果条件为真,则返回0;否则返回非0值。 - 方括号表达式:
[ ]
用于在脚本中进行条件测试,它实际上是一个命令替换的语法,可以与逻辑运算符一起使用。例如,[ -f file.txt ]
与test -f file.txt
是等价的。方括号表达式也返回0或非0值,表示条件的真假。
在Shell脚本中,test
命令和[]
通常可以互换使用,但有一些细微的差别。例如,当使用逻辑运算符如&&
和||
时,[]
不支持旧式的-a
和-o
运算符,而推荐使用&&
和||
。此外,对于模式匹配和正则表达式匹配,通常使用[[ ]]
(双左方括号),而基本的条件测试则可以使用[ ]
或test
命令。
总的来说,虽然test
命令和[]
在功能上是相似的,但它们的使用场景和语法有所不同。在编写Shell脚本时,应根据具体的需求和上下文选择合适的方法进行条件测试。
# Shell 括号的用法
在Shell中,括号有小括号、中括号和大括号。每种括号都有其特定的用途和语法规则。
小括号:
单小括号:
用于命令替换。例如,
echo $(ls)
会执行ls
命令,并将输出作为echo
命令的参数,等同于echo `ls`
。用于命令组合和执行,可以创建一个子shell来顺序执行命令。例如,
(pwd ; ls ; cd /etc ; pwd ; cd ; pwd ; ls)
会创建一个子shell并执行其中的命令。用于初始化数组。例如,
array=(a b c d)
会创建一个包含元素a、b、c、d的数组。
双小括号:
用于算术运算和比较。((表达式))常用于算术运算比较,双括号中的变量可以不使用$符号前缀。
#!/bin/bash #求100以内的偶数 num=2 while ((num<100)) #数值与运算符可以没有空格,变量的使用时也可以不使用$num do echo "$num" ((num=num*2)) done
1
2
3
4
5
6
7
8用于循环语句。例如,
for((i=0;i<5;i++))
可以在双小括号内进行循环变量的递增。
中括号:
单中括号:
- 用于条件表达式,算术比较,例如,
[ $i -ge 1 ]
进行数值比较。 - 用于条件表达式,文件测试,例如,
[ -d $file ]
检测文件是否是目录。 - 字符范围。用作正则表达式的一部分,描述一个匹配的字符范围。例如,
cat 1.txt|grep "[0-9]"
。 - 引用数组中每个元素。例如,
${array_name[2]}
。
- 用于条件表达式,算术比较,例如,
双中括号:
- 用于条件表达式,字符串比较,例如,
[[ hello == hell? ]]
进行字符串模式匹配和正则表达式匹配。在进行字符串比较时,最好使用双中括号 [[ ]]. 因为单中括号可能会导致一些错误,因此最好避开它们。
- 用于条件表达式,字符串比较,例如,
大括号:
- 帮助解释器识别变量的边界。
- 用于变量替换,如
${var:-string}
当变量为空时,将string赋值给var。 - 在序列生成中,如
{1..4}
用于生成数字序列。 - 用于文件名扩展,如
{1,4}.txt
可以生成1.txt和4.txt两个文件,cp /path/to/file.txt{,.backup}
可以在/path/to目录下生成备份文件file.txt.backup。
在Shell脚本中,单中括号[ ]
和双中括号[[ ]]
各有其用途,选择使用哪种括号取决于特定的需求和场景。
- 单中括号
[ ]
:- 主要用于测试条件表达式的返回值,它是一个测试命令,返回0表示真,非0表示假。
- 在进行算术比较或算术运算时,单中括号
[ ]
更为合适。例如,进行数值比较或执行算术运算时,应使用单中括号。 - 单中括号内的表达式需要特别注意空格的使用,例如
[ $a -eq $b ]
,缺少空格可能会导致错误。
- 双中括号
[[ ]]
:- 提供了更强大的字符串处理能力,支持模式匹配和正则表达式,对于字符串和文件名的处理更为灵活。
- 双中括号在条件判断时可以不用引号包围变量,也可以支持逻辑操作符
&&
、||
,并且不需要转义字符。 - 双中括号在语法上更接近于其他编程语言,提供了一定的编程便利性。
总结来说,当需要进行算术比较或运算时,应使用单中括号[ ]
;而当需要进行字符串处理、模式匹配或提供更友好的语法时,应使用双中括号[[ ]]
。在实际应用中,根据具体的需求选择合适的括号可以提高脚本的健壮性和可读性。
# Shell 引号的用法
# Shell 流程控制
# 条件结构
# if 条件结构
if condition
then
command1
command2
...
commandN
fi
# 写成一行
if condition; then command1; command2… fi
2
3
4
5
6
7
8
9
10
# if else 条件结构
if condition
then
command1
command2
...
commandN
else
command
fi
2
3
4
5
6
7
8
9
# if else-if else 条件结构
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
2
3
4
5
6
7
8
9
# case ... esac 多选择条件结构
case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,是一种多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。
可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case ... esac 语法格式:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
2
3
4
5
6
7
8
9
10
11
12
13
14
# 循环结构
# for 循环结构
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
# 写成一行
for var in item1 item2 ... itemN; do command1; command2… done;
# 无限循环语法格式
for (( ; ; ))
do
command
done
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# while 循环结构
while condition
do
command
done
# 无限循环语法格式一
while :
do
command
done
# 无限循环语法格式二
while true
do
command
done
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# until 循环结构
until 循环执行一系列命令直至条件为 true 时停止。
until 循环与 while 循环在处理方式上刚好相反。
until condition
do
command
done
2
3
4
# break 和 continue
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell 使用两个命令来实现该功能:break 和 continue。
break 命令允许跳出所有循环(终止执行后面的所有循环)。
continue 命令与 break 命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
# Shell 函数
Shell 函数定义语法格式:
[ function ] funname [()]
{
action;
[return int;]
}
2
3
4
5
说明:
- 可以带 function fun() 定义,也可以直接 fun() 定义,不带任何参数。
- 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。
- 在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。
- 函数返回值,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return 语句只能返回一个介于 0 到 255 之间的整数。
- 函数返回值在调用该函数后通过 $? 来获得。
# Shell 命令连接
在Shell中,命令连接可以使用多种符号,常见的有以下几种:
类型 | 符号 | 说明 |
---|---|---|
分号 | ; | 无论前一个命令执行成功与否,都会执行下一条命令。 |
& | 多个命令同时执行,不管命令是否执行成功。 | |
逻辑与 | && | 只有前一个命令执行成功时,才会执行下一条命令。 |
逻辑或 | || | 只有前一个命令执行失败时,才会执行下一条命令。 |
管道 | | | 将前一个命令的输出作为后一个命令的输入。 |
# Shell 标准输入/输出和重定向
执行一个shell命令行,系统有三个默认的文件描述符供程序使用。标准输入文件(STDIN),通常对应终端的键盘;标准输出文件(STDOUT)和标准错误输出文件(STDERR),这两个文件都对应终端的屏幕。
使用符合 “>” 将屏幕的输出导入到文件,屏幕不再有显示,“>” 会覆盖之前的内容。
使用符合 “>>” 将屏幕的输出追加到文件,屏幕不再有显示,“>>” 不会覆盖之前的内容。
标准输入用“0”表示。
标准正确输出用 “1” 表示。“1”可以省略。>file
等同于1>file
,>>file
等同于1>>file
标准错误输出用 “2” 表示。
类型 | 操作符 | 用途 |
---|---|---|
重定向输入 | < | 从指定的文件读取数据,而不是从键盘输入 |
重定向输出 | > | 将输出结果保存到指定的文件(覆盖原有内容) |
重定向输出 | >> | 将输出结果追加到指定的文件尾部 |
标准错误输出 | 2> | 将错误信息保存到指定的文件(覆盖原有内容) |
标准错误输出 | 2>> | 将错误信息追加到指定的文件尾部 |
混合输出 | &> | 将标准正确输出、标准错误输出的内容保存到同一文件(覆盖原有内容) |
混合输出 | &>> | 将标准正确输出、标准错误输出的内容追加到指定的文件尾部 |
nohup command >/dev/null 2>&1 &
nohup 英文全称 no hang up(不挂起),用于在系统后台不挂断地运行命令,退出终端不会影响程序的运行。
nohup 命令,在默认情况下(非重定向时),会输出一个名叫 nohup.out 的文件到当前目录下,如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。
nohup 命令语法格式:
nohup command [arg...] &
命令 /dev/null 2>&1 &
的主要作用是将程序的标准输出和错误输出都重定向到 /dev/null
,从而屏蔽这些输出,使得运行该命令的用户不会看到任何输出信息。
这个命令组合可以分解为几个部分来理解:
/dev/null
代表空设备文件,是一个特殊的文件,所有写入它的内容都会被永久丢弃,因此被称为“黑洞”或“垃圾桶”。>/dev/null
等同于1>/dev/null
,将标准错误输出保存到空设备文件。2>&1
是一个shell重定向技巧,它将标准错误输出(文件描述符2)重定向到标准输出(文件描述符1)当前指向的位置。在这个上下文中,由于标准输出也被重定向到了/dev/null
,因此标准错误输出也随之被丢弃。&
在命令的末尾表示将命令放到后台执行,这样用户可以在不等待命令执行完成的情况下继续使用终端。
Linux tee命令用于读取标准输入的数据,并将其内容输出成文件。语法格式:
# 执行command脚本时将错误输出2以及标准输出1追加到nohup.log文件的后面
command 2>&1 | tee -a /path/to/nohup.log
2
# Shell 设置字体颜色
在shell中设置文本颜色,可以使用特殊的转义序列,这些序列会被终端解释为控制指令。常见的转义序列包括ANSI escape codes。
以下是一些基本的ANSI escape codes示例,用于改变文本颜色:
# 语法: \033[<code>m
# 其中<code>是颜色代码
# 文本颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
# 文本背景颜色
RED_BG='\033[0;41m'
GREEN_BG='\033[0;42m'
YELLOW_BG='\033[0;43m'
BLUE_BG='\033[0;44m'
# 重置所有文本属性
RESET='\033[0m'
# 使用示例
echo -e "${RED}这是红色文本${RESET}"
echo -e "${GREEN}这是绿色文本${RESET}"
echo -e "${YELLOW}这是黄色文本${RESET}"
echo -e "${BLUE}这是蓝色文本${RESET}"
echo -e "${RED_BG}红色背景的文本${RESET}"
echo -e "${GREEN_BG}绿色背景的文本${RESET}"
echo -e "${YELLOW_BG}黄色背景的文本${RESET}"
echo -e "${BLUE_BG}蓝色背景的文本${RESET}"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
语法格式:
echo -e "\033[属性;属性m 需要改变的字符串 \033[0m"
-e
表示启用转义字符的解析。
常用ANSI控制码总结如下:
\033[0m:关闭所有属性
\033[1m:设置高亮度
\033[4m:下划线
\033[5m:闪烁
\033[7m:反显,撞色显示,显示为白底黑字,或者显示为黑底白字
\033[8m:消隐,字符颜色将会与背景颜色相同
\033[30m -- \33[37m:设置字符颜色
- 30:黑色
- 31:红色
- 32:绿色
- 33:黄色
- 34:蓝色
- 35:紫色
- 36:浅蓝色
- 37:灰色
\033[40m -- \33[47m:设置背景色
- 40:黑色
- 41:红色
- 42:绿色
- 43:黄色
- 44:蓝色
- 45:紫色
- 46:浅蓝色
- 47:灰色
\033[K:清除从光标到行尾的内容
# source 和 export
在Shell脚本中,可以使用source或者.命令来包含(或者说执行)外部的Shell脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。
语法格式:
source /path/to/filename
或
. /path/to/filename # 注意点号(.)和文件名中间有一空格
2
3
source 命令用于在当前 shell 环境中加载和执行指定的脚本文件,并确保其中的变量、函数等在当前 shell 中可用,而不是启动一个新的子 shell 来执行脚本。
Linux export 命令用于设置或显示环境变量。在 shell 中执行程序时,shell 会提供一组环境变量。export 可新增,修改或删除环境变量,供后续执行的程序使用。export 的效力仅限于该次登陆操作。
语法格式:
export [-fnp] [变量名称]=[变量设置值]
# 导出变量1
export 变量名称=变量设置值
# 导出变量2
变量名称=变量设置值
export 变量名称
# 导出函数
export -f 函数名称
2
3
4
5
6
7
8
9
参数说明:
- -f 代表[变量名称]中为函数名称。
- -n 删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。
- -p 列出所有的shell赋予程序的环境变量。
示例代码:
# 定义变量
my_variable="This is my variable"
# 定义函数
my_function() {
echo "This is my function"
}
# 导出变量
export my_var="This is my var"
export my_variable
# 导出函数
export -f my_function
2
3
4
5
6
7
8
9
10
11
12
13
14
export 命令用于将变量设置为环境变量,使其在当前 shell 中可用,并且在当前 shell 中启动的任何子进程中也可用。
# 相关资料
https://www.runoob.com/linux/linux-shell.html (opens new window)