shell语法
1.头文件
1 | !/bin/bash |
2.运行方式
作为可执行文件
1 | chmod +x test.sh#增加权限 |
用解释器执行
1 | bash test.sh |
3.注释
3.1单行注释
每行中#之后的内容均是注释
3.2多行注释
格式:(EOF可换为其他字符)
1 | :<<EOF |
4.定义变量
1 | name1='yxc' # 单引号定义字符串 |
5.使用变量
使用变量,需要加上 $
符号,或者 ${}
符号。花括号是可选的,主要为了帮助解释器识别变量边界。(最好使用{})
1 | name=yxc |
5.1只读变量
使用 readonly
或者 declare
可以将变量变为只读。
1 | name=yxc |
5.2删除变量
unset
可以删除变量
1 | name=yxc |
6.变量类型
6.1自定义变量(局部变量)
子进程不能访问的变量
6.2环境变量(全局变量)
子进程可以访问的变量
自定义变量改成环境变量:
1 | acs@9e0ebfcd82d7:~$ name=yxc # 定义变量 |
环境变量改为自定义变量:
1 | acs@9e0ebfcd82d7:~$ export name=yxc # 定义环境变量 |
7.字符串
字符串可以用单引号,也可以用双引号,也可以不用引号。
单引号与双引号的区别:
单引号中的内容会原样输出,不会执行、不会取变量;
双引号中的内容可以执行、可以取变量;
1 | name=yxc # 不用引号 |
7.1获取字符串长度
1 | name="yxc" |
7.2提取子串
1 | name="hello,yxc" |
8.默认变量
在执行shell脚本时,可以向脚本传递参数。$1是第一个参数,$2是第二个参数,以此类推。特殊的,$0是文件名(包含路径)。例如:
创建文件test.sh:
1 | ! /bin/bash |
然后执行该脚本
1 | acs@9e0ebfcd82d7:~$ chmod +x test.sh |
其它参数相关变量
9.数组
9.1定义
数组用小括号表示,元素之间用空格隔开。例如:
1 | array=(1 abc "def" yxc) |
也可以直接定义数组中某个元素的值:
1 | array[0]=1 |
9.2读取数组中某个元素的值
格式:
1 | {array[index]} |
1 | array=(1 abc "def" yxc) |
9.3读取整个数组
1 | array=(1 abc "def" yxc) |
9.4数组长度
1 | {#array[@]} # 第一种写法 |
1 | array=(1 abc "def" yxc) |
10.expr命令
expr
命令用于求表达式的值,格式为:
expr
表达式
表达式说明:
用空格隔开每一项
用反斜杠放在shell特定的字符前面(发现表达式运行错误时,可以试试转义)
对包含空格和其他特殊字符的字符串要用引号括起来
expr
会在stdout
中输出结果。如果为逻辑关系表达式,则结果为真,stdout
为1,否则为0。
expr
的exit code
:如果为逻辑关系表达式,则结果为真,exit code
为0,否则为1。
10.1字符串表达式
1.length STRING
返回STRING
的长度
2.index STRING CHARSET
CHARSET中任意单个字符在STRING中最前面的字符位置,下标从1开始。如果在STRING中完全不存在CHARSET中的字符,则返回0。
3.substr STRING POSITION LENGTH
返回STRING
字符串中从POSITION
(下标从1开始)开始,长度最大为LENGTH
的子串。如果POSITION
或LENGTH
为负数,0或非数值,则返回空字符串。
示例:
1 | str="Hello World!" |
10.2整数表达式
expr
支持普通的算术操作,算术表达式优先级低于字符串表达式,高于逻辑关系表达式。
+-
加减运算。两端参数会转换为整数,如果转换失败则报错。
* / %
乘,除,取模运算。两端参数会转换为整数,如果转换失败则报错。
()
可以该表优先级,但需要用反斜杠转义
1 | a=3 |
10.3逻辑关系表达式
|
如果第一个参数非空且非0,则返回第一个参数的值,否则返回第二个参数的值,但要求第二个参数的值也是非空或非0,否则返回0。如果第一个参数是非空或非0时,不会计算第二个参数。&
如果两个参数都非空且非0,则返回第一个参数,否则返回0。如果第一个参为0或为空,则不会计算第二个参数。
< <= = == != >= >
比较两端的参数,如果为true,则返回1,否则返回0。”==”是”=”的同义词。”expr”首先尝试将两端参数转换为整数,并做算术比较,如果转换失败,则按字符集排序规则做字符比较。
()
可以该变优先级,但需要用反斜杠转义
1 | a=3 |
11.read命令
read
命令用于从标准输入中读取单行数据。当读到文件结束符时,exit code
为1,否则为0。
参数说明
-p
: 后面可以接提示信息-t
:后面跟秒数,定义输入字符的等待时间,超过等待时间后会自动忽略此命令
1 | acs@9e0ebfcd82d7:~$ read name # 读入name的值 |
12.echo命令
echo
用于输出字符串。命令格式:
echo STRING
12.1显示普通字符串
1 | echo "Hello AC Terminal" |
12.2显示转义字符
1 | echo "\"Hello AC Terminal\"" # 注意只能使用双引号,如果使用单引号,则不转义 |
12.3显示变量
1 | name=yxc |
12.4显示换行
1 | echo -e "Hi\n" # -e 开启转义 |
12.5显示不换行
1 | echo -e "Hi \c" # -e 开启转义 \c 不换行 |
12.6显示结果定向至文件
1 | echo "Hello World" > output.txt # 将内容以覆盖的方式输出到output.txt中 |
12.7原样输出字符串,不进行转义或取变量(用单引号)
1 | name=acwing |
12.8显示命令的执行结果
1 | echo `date` |
13printf
命令
printf命令用于格式化输出,类似于C/C++中的printf函数。
默认不会在字符串末尾添加换行符。
1 | printf "%10d.\n" 123 # 占10位,右对齐 |
1 | 123. |
14.test命令与判断符号[ ]
14.1逻辑运算符&&和||
&&
表示与,||
表示或
二者具有短路原则:expr1 && expr2
:当expr1
为假时,直接忽略expr2
expr1 || expr2
:当expr1
为真时,直接忽略expr2
表达式的exit code
为0,表示真;为非零,表示假。(与C/C++中的定义相反)
14.2test命令
test
命令用于判断文件类型,以及对变量做比较。
test
命令用exit code
返回结果,而不是使用stdout
。0表示真,非0表示假。
1 | test 2 -lt 3 # 为真,返回值为0 |
1 | acs@9e0ebfcd82d7:~$ ls # 列出当前目录下的所有文件 |
14.3文件类型判断
test -e filename # 判断文件是否存在
14.4文件权限判断
test -r filename # 判断文件是否可读
14.5整数间的比较
1 | test $a -eq $b # a是否等于b |
14.6字符串比较
14.7多重条件判定
1 | test -r filename -a -x filename |
14.8判断符号[]
[]
与test
用法几乎一模一样,更常用于if语句中。另外[[]]
是[]
的加强版,支持的特性更多。
1 | [ 2 -lt 3 ] # 为真,返回值为0 |
1 | acs@9e0ebfcd82d7:~$ ls # 列出当前目录下的所有文件 |
[]
内的每一项都要用空格隔开
中括号内的变量,最好用双引号括起来
中括号内的常数,最好用单或双引号括起来
1 | name="acwing yxc" |
15.判断语句
15.1 if…then形式
类似于C/C++
中的if-else
语句
单层if
1 | if condition |
1 | a=3 |
输出结果:
3在范围内
单层if-else
1 | if condition |
多层if-elif-elif-else
1 | if condition |
15.2case…esac
形式
1 | case $变量名称 in |
16.循环语句
16.1 for...in...do...done
1 | for var in val1 val2 val3 |
示例1,输出a 2 cc,每个元素一行:
1 | for i in a 2 cc |
示例2,输出当前路径下的所有文件名,每个文件名一行:
1 | for file in `ls` |
示例3,输出1-10
1 | for i in $(seq 1 10) |
示例4,使用{1..10}
或者 {a..z}
1 | for i in {a..z} |
16.2 for ((…;…;…)) do…done
命令格式
1 | for ((expression; condition; expression)) |
输出1-10,每行一个
1 | for ((i=1; i<=10; i++)) |
16.3 while…do…done
循环
1 | while condition |
示例,文件结束符为Ctrl+d
,输入文件结束符后read
指令返回false。
1 | while read name |
16.4 until…do…done
循环
1 | until condition |
当用户输入yes
或者YES
时结束,否则一直等待读入
1 | until [ "${word}" == "yes" ] || [ "${word}" == "YES" ] |
16.5 break命令
跳出当前一层循环,break
不能跳出case
语句
1 | while read name |
该示例每读入非EOF的字符串,会输出一遍1-7。
该程序可以输入Ctrl+d
文件结束符来结束,也可以直接用Ctrl+c
杀掉该进程。
16.6 continue命令
跳出当前循环
1 | for ((i=1;i<=10;i++)) |
该程序输出1-10中的所有奇数。
16.7 死循环的处理方式
如果AC Terminal可以打开该程序,则输入Ctrl+c
即可。
否则可以直接关闭进程:
1.使用top命令找到进程的PID
2.输入kill -9 PID
即可关掉此进程
17.函数
bash
中的函数类似于C/C++
中的函数,但return
的返回值与C/C++
不同,返回的是exit code
,取值为0-255
,0表示正常结束。
如果想获取函数的输出结果,可以通过echo
输出到stdout
中,然后通过$(function_name)
来获取stdout
中的结果。
函数的return
值可以通过$?
来获取。
1 | [function] func_name() { # function关键字可以省略 |
不获取 return
值和stdout
值
1 | func() { |
获取 return
值和stdout
值
1 | func() { |
输出结果
1 | output = Hello yxc |
17.1函数的输入参数
在函数内,$1
表示第一个输入参数,$2
表示第二个输入参数,依此类推。
注意:函数内的$0
仍然是文件名,而不是函数名。
1 | func() { # 递归计算 $1 + ($1 - 1) + ($1 - 2) + ... + 0 |
输出结果:
55
17.2函数内的局部变量
可以在函数内定义局部变量,作用范围仅在当前函数内。
可以在递归函数中定义局部变量。
1 | local 变量名=变量值 |
1 | ! /bin/bash |
输出结果:
yxc
第一行为函数内的name变量,第二行为函数外调用name变量,会发现此时该变量不存在。
18.文件重定向
每个进程默认打开3个文件描述符:
stdin
标准输入,从命令行读取数据,文件描述符为0stdout
标准输出,向命令行输出数据,文件描述符为1stderr
标准错误输出,向命令行输出数据,文件描述符为2
可以用文件重定向将这三个文件重定向到其他文件中。
输入和输出重定向
1 | echo -e "Hello \c" > output.txt # 将stdout重定向到output.txt中 |
同时重定向stdin
和stdout
创建bash脚本:
1 | ! /bin/bash |
创建input.txt,里面的内容为:
3 4
执行命令:
1 | acs@9e0ebfcd82d7:~$ chmod +x test.sh # 添加可执行权限 |
19.引入外部脚本
类似于C/C++
中的include
操作,bash
也可以引入其他文件中的代码。
1 | . filename # 注意点和文件名之间有一个空格 |
示例
创建test1.sh
,内容为:
1 | ! /bin/bash |
然后创建test2.sh
,内容为:
1 | ! /bin/bash |
执行命令:
1 | acs@9e0ebfcd82d7:~$ chmod +x test2.sh |