Shell Script 101


学习笔记,非原创

1. 如何运行脚本

1.1. 作为可执行程序

#!/bin/bash
chmod +x ./test.sh  # 使脚本具有执行权限
./test.sh  # 执行脚本

Shebang
位于脚本首行,告诉系统这个脚本需要什么解释器来执行,即使用哪一种 shell。

不可缺少的 ./
一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的程序,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找

1.2. 作为解释器参数

这种方式运行的脚本,不需要 Shebang,即使有也会被忽略。

/bin/sh test.sh
/bin/php test.php

1.3. 命令行参数获取

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。 如”$*”用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如”$@”用「”」括起来的情况、以”$1” “$2” … “$n” 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

实例:test.sh

#!/bin/bash
# author: ShaneTsui
# url:www.shanetsui.com
echo "-- \$* Demo ---"
for i in "$*"; do
    echo $i
done
echo "-- \$@ Demo ---"
for i in "$@"; do
    echo $i
done

测试命令及输出

$ chmod +x test.sh 
$ ./test.sh 1 2 3
-- $* Demo ---
1 2 3
-- $@ Demo ---
1
2
3

2. Variable

2.1. 定义和用法

your_name="qinjx"
echo $your_name
echo ${your_name}

变量定义

  • 变量名和等号之间不能有空格
  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头

变量种类

  • 局部变量: 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
  • 环境变量: 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
  • shell变量: shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行。

Best practice: 花括号
变量名外面的花括号是可选的,加花括号是为了帮助解释器识别变量的边界
推荐给所有变量加上花括号,这是个好的编程习惯

2.2. Readonly

#!/bin/bash
myUrl="https://www.google.com"
readonly myUrl
myUrl="https://www.shanetsui.com" #/bin/sh: NAME: This variable is read only.

2.3. Delete

#!/bin/sh
myUrl="https://www.shanetsui.com"
unset myUrl
echo $myUrl # nothing will be displayed

3. String

your_name='Shane'
str="Hello, I know you are \"$your_name\"! \n"

单引号

  • 任何字符都会原样输出,即使出现变量也无效

双引号

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

3.1. Length

string="abcd"
echo ${#string} #输出 4

3.2. Substring

string="runoob is a great site"
echo ${string:1:4} # 输出 unoo

3.3. Find character index

string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

4. Array

Bash Shell 只支持一维数组(不支持多维数组)

# Definition 1
array_name=(value0 value1 value2 value3)

# Definition 2
array_name=(
value0
value1
value2
value3
)

# Assign value
array_name[0]=value0
array_name[1]=value1
array_name[3]=value3  # No need to use continuous index

echo ${array_name[3]} 
echo ${array_name[@]} # Get all items in array

4.1. Length

# Two equivalent ways to get array length
length=${#array_name[@]}
length=${#array_name[*]}

5. Comment

#--------------------------------------------
# 这是一个单行注释
#--------------------------------------------

# 多行注释
:<< !
  ____                 _    ____                 _
 / ___| ___   ___   __| |  / ___| ___   ___   __| |
| |  _ / _ \ / _ \ / _` | | |  _ / _ \ / _ \ / _` |
| |_| | (_) | (_) | (_| | | |_| | (_) | (_) | (_| |
 \____|\___/ \___/ \__,_|  \____|\___/ \___/ \__,_|

 ____  _             _
/ ___|| |_ _   _  __| |_   _
\___ \| __| | | |/ _` | | | |
 ___) | |_| |_| | (_| | |_| |
|____/ \__|\__,_|\__,_|\__, |
                       |___/
!

Here Document
匿名的 Here Doc 常被用作大段的注释。

6. Operator

6.1. Arithmetic Operators

a=10
b=20

echo `expr $a + $b`
echo `expr $a - $b`
echo `expr $a \* $b`
echo `expr $b / $a`
echo `expr $b % $a`

乘法运算符
乘号 (*) 前边必须加反斜杠 (\) 才能实现乘法运算

数学运算表达式
原生 bash 不支持简单的数学运算,但可以通过其他命令来实现,如 expr。

6.2. Logical operators

if [ $a == $b ]
then
   echo "a 等于 b"
fi

if [ $a != $b ]
then
   echo "a 不等于 b"
fi

空格
条件表达式要放在方括号之间且要有空格。[$a==$b] 是错误的,必须写成 [ $a == $b ]

6.3. Relational Operators

运算符 说明 举例
-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。

6.4. Boolean Operators

运算符 说明 举例
! 非运算,表达式为 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。

6.5. String Operators

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 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。

6.6. File Test Operators

操作符 说明 举例
-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。

7. 流程控制

7.1. if 语句

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

7.2. for 循环

do
    command1
    command2
    ...
    commandN
done

7.3. 多分支选择

case value in
mode1)
    command1
    command2
    command3
    ;;
mode2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

8. Function

[ function ] func [()] {
action;
[return int;]
}

注意事项

  • function 关键字可选。
  • 可以显示加 return 返回。如果不加,将以最后一条命令运行结果作为返回值。

实例:测试脚本和函数

#!/bin/bash
function demoFun1(){
    echo "这是我的第一个 shell 函数"
    return `expr 1 + 1`
}
demoFun1
echo $?
echo $?

# Output
# 这是我的第一个 shell 函数
# 2
# 0

9. 参考资料

  1. https://www.tutorialspoint.com/unix/unix-basic-operators.htm
  2. https://www.runoob.com/linux/linux-shell.html

文章作者: Shane Tsui
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Shane Tsui !

  目录