概述
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" #这也是注释
多行注释:
:<<EOF
第一行注释
第二行注释
EOF
变量
定义变量,不需要加 $ 符号,注意等号两边不可以有空格,使用变量时,变量前面要加 $ 符号
例如:
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命令
expr命令用于求表达式的值,表达式说明:
- 用空格隔开每一项
- 用反斜线放在shell特定的字符前面(当发现表达式运行错误时,可以试试转义)
- 对包含空格和其他特殊字符的字符串要用引号引起来
- expr命令会在 sdout 中输出结果,如果是逻辑表达式,若结果为真,则输出1,否则为0
- expr命令的 exit code :如果为逻辑关系表达式,若结果为真, exit code 为0,否则为1
字符串表达式:
- length string – 返回字符串string的长度
- index string charset – charset 任意单个字符在string中最前面的字符位置,下标从1开始,如果在string中完全不存在 charset 的字符,则返回0
- substr string position length – 返回string字符串中从position开始,长度为length的子串;如果position或者length为负数、0或非数值,则返回空字符串
例如:
#! /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
逻辑关系表达式
- | :如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。
- &:如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。
- < <= = == != >= >:比较两端的参数,如果为true,则返回1,否则返回0。”==”是”=”的同义词。”expr”首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。
例如:
#! /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命令
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命令用于输出字符串
命令格式为:
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命令
printf命令用于格式化输出,类似于 C\C++ 中的printf函数
默认不会在字符串末尾添加换行符
例如:
#! /bin/bash
printf "%10d.\n" 123 #占10位,右对齐
printf "%-10f.2f.\n" 123.1433223 #占10位,保留两位小数,左对齐
printf "My name is %s\n" "sun" #格式化输出字符串
printf "%d * %d = %d\n" 2 3 `expr 2 \* 3` #表达式的值作为参数
test命令与判断符号[]
&& 表示与,||表示或
二者具有短路原则:
expr1 && expr2:当expr1为假时,expr2直接不做了
expr1 || expr2:当expr1为真时,expr2直接不做了
表达式中的 exit code 为0,表示真;为非零,表示假
test命令
在命令行中输入 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 | 两条件是否同时成立 |
-o | 两条件是否至少少一个成立 |
! | 取反,如 test !-x file,当file不可执行时,返回true |
判断符号[]
[]与test用法几乎一模一样,更常用于if语句中;另外[[]]是[]的加强版,支持的特性更多
例如:
[ 2 -lt 3 ] #为真,返回0
echo $? #返回上一条命令的返回值,输出0
注意:
- []中的每一项都要用空格隔开
- 括号内的变量,最好用引号引起来
- 括号内的常数,最好用单或双引号括起来
例如:
name="sun tong"
[ $name == "sun tong" ] #错误 等价于 [ sun tong == "sun tong" ],参数太多,有空格
[ "$name" == "sun tong" ] #正确