shell是我们通过命令行与操作系统沟通的语言
shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用
Linux中有很多常见的shell脚本:我们最常用的就是bash,也是Linux系统一般默认使用的。
文件开头需要写:#! /bin/bash ---------指明bash为脚本解释器
脚本创建示例:
#! /bin/bash
echo "hello world"
运行方式:
acs@fb883ed03006:~$ chmod +x test.sh #使脚本具有可执行权限
acs@fb883ed03006:~$ ./test.sh #当前路径下执行
hello world #脚本输出
acs@fb883ed03006:~$ /home/acs/test.sh #绝对路径下执行
hello world
acs@fb883ed03006:~$ ~/test.sh #家目录路径下执行
hello world
用解释器执行(不需要权限):
acs@fb883ed03006:~$ bash test.sh
hello world
注意:用解释器执行不需要有权限,作为可执行文件来执行一定要有权限
单行中 # 之后的内容均是注释
# 这是一行注释
echo "hello world" #这也是注释
多行注释:
:<定义变量,不需要加 $ 符号,注意等号两边不可以有空格,使用变量时,变量前面要加 $ 符号
例如:
name1='sun' #单引号定义字符串
name2="sun" #双引号定义字符串
name3=sun #可以不加引号,也可以定义字符串
echo $name1 #输出sun
echo ${name1} #这种更为规范
echo ${name1}tong #输出suntong
只读变量:使用readomly或者declare可以将变量设置为只读状态
name=sun
readonly name
declare -r name #两种写法均可
name=st #会报错,因为这时候name是只读变量
删除变量:unset可以删除变量
name=sun
unset name
echo $name #输出空行
变量类型
自定义变量改为环境变量
name=sun
export name #第一种方法
declare -x name #第二种方法
环境变量改为自定义变量
export name=sun #定义环境变量
declare +x name #定义为自定义变量
字符串:字符串可以使单引号,也可以是双引号,也可以不用引号
单引号和双引号的区别:
name=sun
echo "hello, $name \"hh\"" #双引号,输出 hello,sun "hh"
echo 'hello, $name \"hh"' #单引号,输出 hello, $name \"hh\"
注意:不用引号是和双引号的效果是一样的
获取字符串长度:用 # + 字符串
name="sun"
echo ${#name} #输出3
提取子串
name="hello sun"
echo ${name:0:5} #提取从0开始的5个字符,会输出hello
注意:字符串的区间是左闭右开,从0开始
文件参数变量
在执行shell脚本时,可以向脚本传递参数。$1是第一个参数,$2是第二个参数,以此类推,特殊的,$0是文件名
(包含路径)
#! /bin/bash
echo "文件名:"$0
echo "第一个参数:"$1
echo "第二个参数:"$2
echo "第三个参数:"$3
然后执行该脚本:
acs@fb883ed03006:~$ chmod +x test.sh
acs@fb883ed03006:~$ ./test.sh 1 2 3 4
文件名:./test.sh
第一个参数:1
第二个参数:2
第三个参数:3
注意:向脚本传递参数大于一位时,需要用大括号括起来;例如 echo {10}
其他参数相关变量

数组中可以存放多种不同类型的值,只支持一维数组,初始化时不需要指明数组的大小
数组下标是从0开始的
定义:数组用小括号表示,元素之间用空格隔开
例如:
array=(1 abc "sun" sun)
也可以直接定义数组中某个元素的值
array[0]=1
array[1]=abc
array[2]="sun"
array[3]=sun
读取数组中某个元素的值
${array[index]}
#例如
echo ${array[0]}
echo ${array[1]}
echo ${array[2]}
echo ${array[3]}
读取整个数组
${array[@]} #第一种写法
${array[*]} #第二种写法
数组长度:类似于字符串
${#array[@]} #第一种写法
${#array[*]} #第二种写法
expr命令用于求表达式的值,表达式说明:
字符串表达式:
例如:
#! /bin/bash
str="hello world"
echo `expr length "$str"` #``不是单引号,表示执行该命令,输出11
echo `expr index "$str" aWd` #输出11,下标从1开始
echo `expr substr "$str" 2 3` #输出 ell

整数表达式:
expr支持普通的算术运算,算术表达式优先级低于字符串表达式,高于逻辑关系表达式
+/-:加减运算,两端参数会转换为整数,如果转换失败则会报错
、* / %:乘、除、取模运算,两端参数会转换为整数,若转换失败则会报错
():可以改变优先级,但是需要反斜杠进行转义
例如:
#! /bin/bash
a=3
b=4
echo `expr $a + $b` #输出7
echo `expr $a - $b` #输出-1
echo `expr $a \* $b` #输出12,*需要转义
echo `expr $a / $b` #输出0,整除
echo `expr $a % $b` #输出3
echo `expr \( $a + 1 \) \* \( $b + 1 \)` #输出20

逻辑关系表达式
例如:
#! /bin/bash
a=3
b=4
echo `expr $a \> $b` #输出0,>需要转义
echo `expr $a '<' $b` #输出1,<也需要转义,转义也可以使用单引号引起来
echo `expr $a '>=' $b` #输出0
echo `expr $a '<=' $b` #输出1
c=0
d=5
echo `expr $c \& $d` #输出0
echo `expr $a \& $b` #输出3
echo `expr $c \| $d` #输出5
echo `expr $a \| $b` #输出3

read命令用于从标准输入中读取单行数据;当读到文件结束符时,exit code 为1,否则为0
参数说明:
-p:后面可以接提示信息
-t:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令
例如:
#! /bin/bash
read name #读入name的值
echo $name #输出name的值
read -p "Please input your name: " -t 30 age #读入age的值,等待时间为30s
echo $age #输出age的值

echo命令用于输出字符串
命令格式为:
echo string
显示普通字符
echo "hello suntong"
echo hello suntong #引号可以省略
显示转义字符
echo "\"hello suntong\"" #注意只能使用双引号,如果使用单引号,则不能发生转义
echo \"hello suntong\" #可以省略双引号

显示变量
name=sun
echo "My name is $name" #输出My name is sun
显示换行
echo -e "Hi\n" #-e 开启转义
echo "sun"

显示不换行
echo -e "Hi \c" #-e开启转义 \c不换行
echo "sun"

显示结果定向至文件
echo "hello world" > output.txt #将内容以覆盖的方式输出到 output.txt 中

原样输出字符串,不进行转义或取变量(用单引号)
name=sun
echo 'hello $sun\"' #输出 hello $sun\"
显示命令的执行结果
echo `date`

printf命令用于格式化输出,类似于 C\C++ 中的printf函数
默认不会在字符串末尾添加换行符
例如:
#! /bin/bash
printf "%10d\n" 123 #占10位,右对齐
printf "%-102f\n" 123.1433223 #占10位,保留两位小数,左对齐
printf "My name is %s\n" "sun" #格式化输出字符串
printf "%d * %d = %d\n" 2 3 `expr 2 \* 3` #表达式的值作为参数
第一个没有点,第二个输出错误

&& 表示与,||表示或
二者具有短路原则:
expr1 && expr2:当expr1为假时,expr2直接不做了
expr1 || expr2:当expr1为真时,expr2直接不做了
表达式中的 exit code 为0,表示真;为非零,表示假
在命令行中输入 man test,可以查看test命令的用法
test命令用于判断文件类型,以及对变量作比较
test命令用 exit code 返回结果,而不是使用sdout;0表示真,非0表示假
例如:
#! /bin/bash
test 2 -lt 3 #为真,返回值为0
echo $? #输出上个命令的返回值,输出0

可以用来判断文件是否存在,也可以实现if语句

文件类型判断
| 测试参数 | 代表意义 |
|---|---|
| -e | 文件是否存在 |
| -f | 是否为文件 |
| -d | 是否为目录(文件夹) |
例如:
acs@fb883ed03006:~$ test -e main.sh
acs@fb883ed03006:~$ echo $?
0
文件权限判断
| 测试参数 | 代表意义 |
|---|---|
| -r | 文件是否可读 |
| -w | 文件是否可写 |
| -x | 文件是否可执行 |
| -s | 文件是否为空文件 |
例如:
acs@fb883ed03006:~$ test -x main.sh
acs@fb883ed03006:~$ echo $?
0
acs@fb883ed03006:~$ test -r homework
acs@fb883ed03006:~$ echo $?
0
acs@fb883ed03006:~$ test -w homework
acs@fb883ed03006:~$ echo $?
0
整数间的比较
| 测试参数 | 代表意义 |
|---|---|
| -eq | 是否相等 |
| -ne | 是否不相等 |
| -gt | 是否大于 |
| -lt | 是否小于 |
| -ge | 是否大于等于 |
| -le | 是否小于等于 |
例如:
acs@fb883ed03006:~$ a=3
acs@fb883ed03006:~$ b=4
acs@fb883ed03006:~$ test $a -lt $b
acs@fb883ed03006:~$ echo $?
0
acs@fb883ed03006:~$ test $a -eq $b
acs@fb883ed03006:~$ echo $?
1
字符串比较
| 测试参数 | 代表意义 |
|---|---|
| test -z string | 判断string是否为空,如果为空,则返回true |
| test -n string | 判断string是否非空,如果非空,则返回true,(-n可以省略) |
| test str1 == str2 | 判断str1是否等于str2 |
| test str1 != str2 | 判断str1是否不等于str2 |
多重条件判定 (与或非)
| 测试参数 | 代表意义 |
|---|---|
| -a | 两条件是否同时成立 (and) |
| -o | 两条件是否至少少一个成立(or) |
| ! | 取反,如 test !-x file,当file不可执行时,返回true |
例如:
test -r test.sh -a -w test.sh && echo "true" || echo "false"
[]与test用法几乎一模一样,更常用于if语句中;另外[[]]是[]的加强版,支持的特性更多
例如:
[ 2 -lt 3 ] #为真,返回0
echo $? #返回上一条命令的返回值,输出0
注意:
例如:
name="sun tong"
[ $name == "sun tong" ] #错误 等价于 [ sun tong == "sun tong" ],参数太多,有空格
[ "$name" == "sun tong" ] #正确