shell 是弱类型语言,这跟 PHP 等弱类型脚本语言类似。
参考资料
在线编辑器
1. 语法
shell 以 #
开头的行就是注释,只有单行注释,没有多行注释,只能每一行加一个 #
号。
1.1 变量
shell 中使用 echo
打印内容,默认输出到 STDOUT(即终端窗口)中。
用户自定义变量
定义变量
定义变量时,变量名不加美元符号($
)。注意,变量名和等号之间不能有空格。
除了显式地直接赋值,还可以用语句给变量赋值。
a=666
s="hello"usr var
shell 中可以使用命令,语法为 $(command)
:
c=$(pwd) # /root/shell
d=$(ls /) # bin boot data dev etc ... root run sbin srv sys tmp
使用变量
使用变量时支持两种语法,都需要在变量名前面加美元符号:
$var
:在变量名前加$
符号即可使用变量${var}
:将变量放在${}
的大括号中,需要识别边界时,必须使用大括号
a=666
s="hello"
echo $a
echo ${a} # 一般情况下,大括号可用可不用
echo "$a"
echo "${s}world" # 需要识别边界时,必须使用大括号
echo "$aworld" # 这种情况无法识别边界,输出为空
为了帮助解释器识别变量的边界,变量名的外面可以添加花括号。推荐给所有变量加上花括号。
重定义变量
已定义的变量,可以被重新定义,如:
a=666
echo $a
a="hello"
echo $a
shell 中的变量类型可以改变。
环境变量
Linux 系统有多个内置的环境变量(通过 env
命令可以查看所有环境变量),且用户可以添加或删除环境变量。注意,环境变量区分大小写。
最常见的 PATH 环境变量,用冒号分割路径:
echo $PATH #/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PATH=$PATH:/root
echo $PATH #/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root
特殊变量
[root@VM_139_38_centos shell]# ./test.sh a b "c d" e
./test.sh
a
4
./test.sh: line 8: asdf: command not found
127
a b c d e
a b c d e
[root@VM_139_38_centos shell]# cat test.sh
#!/bin/bash
echo $0
echo $1
echo $#
asdf
echo $?
echo $*
echo $@
[root@VM_139_38_centos shell]# cat test.sh
#!/bin/bash
echo $0
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
[root@VM_139_38_centos shell]# /root/test/shell/test.sh a b "c d" e
/root/test/shell/test.sh
-- $* 演示 ---
a b c d e
-- $@ 演示 ---
a
b
c d
e
$n
在脚本中,$0
变量表示当前脚本名,$1
至 $9
表示执行脚本时传入的第一个至第九个参数。如果参数占两位数字,需要用大括号,例如 ${11}
。
$#
获取所有输入参数的个数,可以用于循环。
类似 ${#a}
可以计算字符串的字符个数。
$*
和 $@
$*
:代表命令行中所有的参数,把所有参数看成一个整体$@
:代表命令行中所有的参数,把每个参数区分对待,可以在循环中取出
$?
最后一条执行的命令的返回码。0表示最后一个命令正确执行,非0表示失败。
[root@VM_139_38_centos ~]# $?
-bash: 0: command not found
[root@VM_139_38_centos ~]# echo $?
127
[root@VM_139_38_centos ~]# ls
acme mysql nohup.out swoole test tmux-client-14353.log
[root@VM_139_38_centos ~]# echo $?
0
$$
脚本运行的当前进程ID号。
脚本入参的判断
为了防止错误,可以在脚本中添加对入参的判断语句:
if [ ! -n "$1" ]; then
echo "no param input"
exit
else
param=$1
fi
1.2 字符串
shell 中的字符串可以用单引号,可以用双引号,也可以不用引号。单双引号的区别跟 PHP 类似。
单引号
str='hello world'
单引号字符串的限制:
- 单引号中不识别变量,原样输出
- 单引号字串中不能出现单引号(对单引号使用转义符后也不行)
双引号
str='hello world'
echo "你好,世界!\"$str\"" #你好,世界!"hello world"
双引号特点:
- 双引号中可以识别变量
- 双引号中可以识别转义字符
字符串操作
拼接字符串
shell 中字符串直接连到一起即可,不需要任何连接字符。也可以将字符串变量放在双引号字符串中的合适位置。
s="world"
s1="hello, "$s" !"
s2="hello, ${s} !"
echo $s $s
获取字符串长度:
直接用 ${#字符串变量名}
就可以获得字符串长度:
s="hello"
echo ${#s} # 5
提取子字符串
直接用 ${字符串变量名:start:length}
就可以获得子字符串:
s="hello world"
echo ${s:1:4} #输出:ello
1.3 数学运算
shell 中进行数学运算的方法挺多,下面一一列举。
简单运算
let
命令、[]、(()) 的使用方法类似。
1. let
命令
let
命令是 bash 内置命令,可以实现简单的算术运算和逻辑运算。可以使用 help let
命令查看具体用法。常见用法:
#!/bin/sh
i=10
echo $i
let i=i+10
echo $i #20
let "i=i+100"
echo $i #120
2. []
i=10
i=$[i+10]
echo $i
i=$[i+100]
echo $i
3. (())
i=10
i=$((i+10))
echo $i
i=$((i+100))
echo $i
高级运算
1. expr
使用 expr 时,变量与算术运算符之间需要加空格,且乘号需要转义。
i=10
i=`expr $i + 10` #20
echo $i
i=`expr $i + 100` #120
echo $i
不加空格时,情况如下:
i=10
i=`expr $i + 10` #10+10
echo $i
i=`expr $i + 100` #10+10+100
echo $i
2. bc
命令
bc
命令支持浮点运算和数学函数调用。
i=10
j=3
m=`echo "scale=9; $i / $j" | bc` #3.33333
echo $m
1.4 数组
Bash Shell 只支持一维数组,初始化时不需要定义数组大小(与 PHP 类似),元素下标由0开始。
Shell 数组用括号来表示,元素用"空格"分割,语法格式如下:
array_name=(value1 ... valuen)
array_name[0]=value0
读取数组
读取数组元素值的一般格式是:
${array_name[index]}
使用 @ 或 * 可以获取数组中的所有元素,用 # 获取数组的长度,例如:
echo "所有元素为:${my_array[*]}"
echo "所有元素为:${my_array[@]}"
echo "数组长度为:${my_array[#]}"
示例:
arr=(1 2 hello "h h h")
for i in ${arr[@]}
do
echo $i
done
输出为:
1
2
hello
h
h
h
1.5 控制语句
控制语句使用 if/else/fi 语法,语法:
if condition
then
command1
command2
...
commandN
elif condition2
command2
else
commandN
fi
示例:
if [[ 3 > 7 ]]; then
echo "3 > 7"
else
echo "3 <= 7"
fi
可以使用的数值比较符号有:
比较符 | 描述 |
---|---|
n1 -eq n2 | 检查 n1 是否等于 n2 |
n1 -ge n2 | 检查 n1 是否大于或等于 n2 |
n1 -gt n2 | 检查 n1 是否大于 n2 |
n1 -le n2 | 检查 n1 是否小于或等于 n2 |
n1 -lt n2 | 检查 n1 是否小于 n2 |
n1 -ne n2 | 检查 n1 是否不等于 n2 |
可以使用的字符串比较:
比较符 | 描述 |
---|---|
str1 = str2 | 检查 str1 是否和 str2 相同 |
str1 != str2 | 检查 str1 是否和 str2 不同 |
str1 < str2 | 检查 str1 是否比 str2 小 |
str1 > str2 | 检查 str1 是否比 str2 大 |
-n str1 | 检查 str1 的长度是否非 0 |
-z str1 | 检查 str1 的长度是否为 0 |
文件比较:
比较符 | 描述 |
---|---|
-d file | 检查 file 是否存在并是一个目录 |
-e file | 检查 file 是否存在 |
-f file | 检查 file 是否存在并是一个文件 |
-r file | 检查 file 是否存在并可读 |
-s file | 检查 file 是否存在并非空 |
-w file | 检查 file 是否存在并可写 |
-x file | 检查 file 是否存在并可执行 |
-O file | 检查 file 是否存在并属当前用户所有 |
-G file | 检查 file 是否存在并且默认组与当前用户相同 |
file1 -nt file2 | 检查 file1 是否比 file2 新 |
file1 -ot file2 | 检查 file1 是否比 file2 旧 |
1.6 循环语句
for
for 循环语法一(for in 格式):
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
写成一行:
for var in item1 item2 ... itemN; do command1; command2… done;
语法二(C 语言风格):
for (( EXP1; EXP2; EXP3 ))
do
command1
command2
command3
done
示例:
sum = 0
for ((i = 0; i < 10; i++)); do
sum = $[sum + $i]
done
echo $sum
while
while 循环语法:
while condition
do
command
done
无限循环:
while :
do
command
done
1.7 函数
函数定义
shell 中可以自定义函数,然后在shell脚本中可以随便调用。函数定义格式如下:
[ function ] funname [()]
{
action;
[return int;]
}
说明:
1、函数定义的关键字 function 可用可不用
2、参数返回值可用可不用。如果不加,将以最后一条命令运行结果,作为返回值。如果加,return 的数值范围是 0-255
下面的例子定义了一个函数并进行调用:
#!/bin/bash
myFun() {
echo "hello function"
}
myFun
函数参数
Shell 中调函数时可以传参。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数…
带参数的函数示例:
myFun() {
echo $#
echo $1
echo $2
echo $0
}
myFun 1 "hello function"
输出为:
2
1
hello function
/tmp/820834436/main.sh
2. 文件操作
2.1 文件读取
2.2 文件写入
2.3 文件包含
Shell 可以包含外部脚本,可以很方便的封装一些公用的代码作为一个独立的文件。被包含的文件 test1.sh 不需要可执行权限。语法格式如下:
. filename # 注意点号(.)和文件名中间有一空格
或
source filename