Shell 变量

定义

定义变量时,变量名和等号之间不能有空格,命名规则如下:

  1. 只能使用英文字母、数字和下划线,首个字符不能为数字
  2. 中间不能有空格, 使用下划线代替
  3. 不能使用标点符号
  4. 不能使用 bash 中的关键字

使用

使用一个定义过的变量,在变量名前面加美元符号,如

1
2
user='DF'
echo $user

也可以添加花括号帮助解释器识别变量的边界

1
2
user='DF'
echo "This callable from ${user}'s bash"

只读变量

使用readonly设置只读变量

1
2
3
#!/bin/bash
user='DF'
readonly user

删除变量

使用unset删除变量

1
unser user

变量类型

运行 shell 时,存在 环境变量、shell 变量、局部变量 三种

  1. 环境变量就是系统变量;
  2. shell 变量是由 shell 程序设置的特殊变量,一部分是环境变量;一部分为局部变量;
  3. 在脚本或命令中定义的,仅在当前 shell 实例中有效的变量。

Shell 字符串

单引号

1
str='this is a string'

单引号中的任何字符都会以原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单独一个的单引号(使用转义符也不行),但可以成对使用,用于字符串拼接。

双引号

1
2
user='DF'
str="this mechine is named of ${user}"

双引号里面可以有变量,可以出现转义字符。

字符串拼接

1
2
3
4
5
6
7
user='DF'
id='0001'

temp1='name:'$user' id:'$id''

temp2="name:${user} id:${id}"
temp3="name:"$user" id:"$id""

字符串长度

1
2
string='abcd'
echo ${#string}

提取子字符串

1
2
str='abcdefghigklmn'
echo ${str:2:5}

查找子字符串

1
2
3
str = 'ABCDEFGHIGKLMN'

echo `expr index "$str" B`

数组

用括号表示数组,数组元素用“空格”符号分割开

1
name=(df ddf dff ddff)

使用 name[] 索引,使用@获取所有元素

1
2
3
4
5
echo ${name[0]} # df
echo ${name[1]} # ddf
echo ${name[2]} # dff
echo ${name[4]} # ddff
echo ${name[@]}

数组长度

1
2
echo ${#name[*]}
echo ${#name[@]}

注释

单行注释使用#
多行注释使用:<<

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#-------------------
# 这是一个bash文件
# 作者为DF
#-------------------

:<<!
这是一个bash文件
作者为DF
!

:<<EOF
这是一个bash文件
作者为DF
EOF

Shell 传递参数

从命令行想 Shell 脚本传递参数,脚本内通过$n (n=0,1,2...)获取
还存在几个特殊字符用于处理参数

命令 含义
$# 传递到脚本参数的数量
$* 以一个字符串的形式返回所有参数
$@ 以不同字符串的形式返回传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程 ID 号
$- 显示Shell使用的当前选项
$? 显示最后命令的退出状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# test.sh
#!/bin/bash
echo '$*'
for i in "$*";do
echo $i
done
echo '$@'
for i in "$@";do
echo $i
done

# 命令行
bash test.sh 1 2 3

# 输出
$*
1 2 3
$@
1
2
3

基本运算符

算数运算符

原生的 bash 中不支持简单的数学运算,但可以利用expr或者awk实现,常用的为expr

1
2
3
4
5
6
7
8
#!/bin/bash
echo `expr 1 + 1` # 加法运算,输出2
echo `expr 1 - 1` # 减法运算,输出0
echo `expr 2 \* 2 ` # 乘法运算,输出4
echo `expr 2 / 2` # 触发运算,输出1
echo `expr 2 % 2` # 取余运算,输出0
[ 2 == 2 ] # 判断相等,返回true
[ 2 != 2 ] # 判断不等,返回false

注意:条件表达式要放在方括号中间,并且要加空格,这与赋值表达式不
   表达式需要被 ` ` 包围

关系运算符

运算符 说明 示例
-eq 判断两边相等 [ 10 -eq 10 ] 返回 true
-ne 判断两边不等 [ 10 -ne 10 ] 返回 false
-gt 判断左边大于右边 [ 10 -gt 15 ] 返回 false
-lt 判断左边小于右边 [ 10 -lt 15 ] 返回 true
-ge 判断左边大于等于右边 [ 15 -ge 15 ] 返回 true
-le 判断左边小于等于右边 [ 15 -le 15 ] 返回 true

布尔运算符

运算符 说明 示例
! 非运算 [ !false ] 返回 true
-o 或运算 [ true -o false ] 返回 true
-a 与运算 [ true -a false ] 返回 false

逻辑运算符

运算符 说明 示例
&& 逻辑 AND [[ true && false ]] 返回 false
|| 逻辑 OR [[ true || false ]] 返回 true

补充:布尔运算符与逻辑运算符的区别

1
2
3
4
5
6
1. 语法方面
布尔运算符使用 [单括号];而逻辑运算符使用 [[双括号]]
2. 运算方面
逻辑运算符具有特殊的短路功能,可以利用这一特性实现用命令 1 的执行结果控制命令 2 执行的效果
[[ cmd1 && cmd2 ]] 当 cmd1==false 时,cmd2 不执行
[[ cmd1 || cmd2 ]] 当 cmd1==true 时,cmd2 不执行

补充: shell 中的状态码

1
2
3
shell 中每个表达式执行完退出时,都会返回一个状态码(exit status 0~255),在这些状态码中,0 表示执行成功,1~255 为退出的状态代码。
在判断语句中,[condition]为判断符,其中条件为真返回 0,假返回 1。
在 C 语言中,存在 while(1)的用法,但与 shell 中 if[ 1 ]的表达不同,c 语言中`1`表示为 True;而 shell 中[ num ]返回状态码 0,无论 num 具体为何数,均返回状态码 0。

字符串运算符

运算符 说明 示例
= 判断两个字符串是否相等 [ abc = abc ] 返回 true
!= 判断两个字符串是否不等 [ abc != abc] 返回 false
-z 判断字符串长度是否为零 [ -z abc] 返回 false
-n 判断字符串长度是否不为零 [ -n abc] 返回 true
$ 检测字符串是否为空 [ $ ‘’ ] 返回 true

文件测试运算符

用于测试 Unix 文件的各种属性

运算符 说明
-d file 是否是目录
-f file 是否是普通文件
-r file 是否可读
-w file 是否可写
-x file 是否可执行
-s file 是否为空
-e file 检擦文件或目录是否存在

echo 命令

1
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
29
30
31
# 显示普通字符串(双引号可以省略)
echo "are you ok"
echo are you ok

# 显示转义字符
echo \" are you ok \"
echo "\" are you ok \""

# 显示变量
# read命令读取一行标准输入
read name
echo "$name are you ok"

# 显示换行
# -e 开启转义
echo -e "are you ok \n"

# 不换行
echo -e "are you ok \c"

# 显示结果重定向至文件
echo "are you ok" >> leijun

# 原样输出字符串
# 不进行转义或取变量
# 用单引号
echo '${leijun}: are you ok'

# 显示命令执行结果
# 使用反引号
echo `date`

printf 命令

1
2
3
4
5
6
7
8
9
printf format-string [arguments]

# printf不自动添加换行符

# %d %s %c 格式替代符
# %-10s 表示宽度为10个字符,'-'表示左对齐,没有则表示右对齐
# %-4.2f .2表示保留两位小数
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234

流程控制

if 条件语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if condition
then
command
fi

if condition
then
command1
else
command2
fi

if condition1
then
command1
elif
command2
else
command3
fi

for 循环语句

1
2
3
4
for var in item1 item2 item3
do
command
done

while 循环语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
while condition
do
command
done

# 无限循环
# 用 : 或 true
while :
do
command
done

# 或者用for
for (( ; ; ))

until 循环

1
2
3
4
until condition
do
command
done

case

1
2
3
4
5
6
7
8
9
10
11
case var in
condition1)
command
;;
condition2)
command
;;
*)
command
;;
esac

break and continue

函数

1
2
3
4
5
function funcname()
{
command
return var
}
  1. 函数定义时,可以待 function,也可以没有;但函数必须在使用前定义;
  2. 当存在 return 语句时,返回后面的内容;否则,返回最后一条命令运行的结果;
  3. 函数返回值通过 $? 获得
  4. 在函数体内部,函数的参数通过$n获得;当 n>=10 时,需采用${n}

输入/输出重定向

大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回 ​​ 到您的终端。一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。

命令 说明
command > file 输出重定向到 file
command < file 输入重定向到 file
command >> file 输入追加到 file
n > file 将文件描述符为 n 的文件重定向到 file
n >> file 将文件描述符为 n 的文件追加到 file
n >& m 将输出文件 m 和 n 合并
n <& m 将输入文件 m 和 n 合并
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入

补充:文件描述符,0 是标准输入,1 是标准输出,2 是标准错误输出

示例

1
2
3
4
5
6
7
8
9
10
# 将 stderr 重定向到file
command 2 > file

# 将 stderr 追加到file
command 2 >> file

# 将 stdout 和 stderr 合并后重定向到file
command > file 2>&1
# 追加
command >> file 2>&1

/dev/null

写入到 /dev/null 的内容都会被其丢弃,并且从其中读不到任何东西,将输出重定向到此文件,可以起到“禁止输出”的效果。

文件包含

1
2
3
. filename
# 或
source filename

Shell 中各种括号的作用

()

  • 命令组 括号中的命令会新开一个子 shell 按顺序执行,同时也因此导致括号中的变量不能被其他部分使用;括号中的多个命令使用;分隔开,最后一个命令不用分号,命令与括号之间无需空格
  • 命令替换 $(command) 相当于 `cmd`
  • 初始化数组 array=(a b c)

(())

  • 整数拓展 整数型的计算((expression)),如果表达式结果为 0,则返回状态码 1;表达式结果非零,则返回状态码 0
  • 运算 $((expression))可以进行符合 C 语言运算规则的运算
  • 重定义变量 a=5;((a++))将$a 重定义为 6
  • 算术运算比较,双括号中的变量可以不使用$前缀,多个表达式用逗号分开。for((i=0;i<5;i++))

[]

  • 内部命令,与 test 等同 可以用于条件判断,运算比较表达式或者条件测试,根据比较结果返回状态码
  • []与 test 中可以使用的运算比较符只有==和!=,两者都是用于字符串比较,不可用于整数比较,整数比较只能使用-eq、-gt 等,同时通过转义字符,可以使用大于号和小于号,逻辑与和逻辑或通过-a 和-o 实现。
  • 字符范围 作为正则表达式的一部分
  • 引用数组中的元素

[[]]

  • [[是 bash 中的关键字
  • 支持字符串的模式匹配,使用=~操作符时支持 shell 的正则表达式
  • 使用[[]]进行条件判断时,可以使用逻辑操作符
  • bash 把[[]]中的表达式看作为一个单独的元素,并返回一个退出状态码。

{}

  • 大括号拓展对文件名作拓展。touch {a,b}.txt 或 touch {a..b}.txt

  • 代码块见多条命令中的第二种

  • 替换结构

    1
    2
    3
    4
    ${var:-string} # 若var为空,则用string替换${var:-string};若var不为空,则用var替换${var:-string}
    ${var:=string} # 若var为空,则用string替换${var:-string},并且将string的值赋给var;若var不为空,则用var替换${var:-string}
    ${var:+string} # 若var为空,则${var:-string}为空;若var不为空,则用var替换${var:-string}
    ${var:?string} # 若var不为空,则用var替换${var:-string};若var为空,则把string输出到标准错误中,并从脚本中退出。
  • 提取和替换字符串

$后的括号

  1. ${a} 变量 a 的值
  2. ${cmd} 命令替换
  3. $((expression)) 计算括号中的数值

多条命令

1
2
3
4
5
# 新开一个shell顺序执行命令,最后一个命令后可以没有分号
(cmd1;cmd2;cmd3)

# 当前shell顺序执行命令,第一个命令与左括号用空格隔开,最后一个命令后面必须有分号
{ cmd1;cmd2;cmd3;}