一 介绍
bash shell是一个与sh兼容的命令行解析器,是用户与系统内核交互的接口。通过bash,可以执行命令(程序),bash本身就内置了很多常用的命令。可以将一些常用的命令写入脚本中,让bash运行,用以实现简化和自动化日常的任务。对于其他比较复杂的任务,如字符串操作、算术、数据访问、更强的函数等功能,尽管bash也提供了对应的语法(也有函数!!),但还是应该选择使用其他脚本(python)或编译语言(c)。因此,这里只记录比较常用的bash语法。
二 启动
shel按照启动方式的不同,可分为login
、non-login
、interactive
、non-interactive
shell。login shell
表示该shell用来登录;interactive shell
的标准输入输出都连接到终端上,即可与用户交互。
shell在启动时会读取配置文件,不同的shell读取的文件都不同。下面是bash shell在不同启动方式下,与执行的配置文件的关系:
- login、interactive bash:即命令行登录时用的shell,先读取和执行
/etc/profile
,然后查找~/.bash_profile
,~/.bash_login
和~/.profile
,读取和执行第一个找到的文件。当shell结束时,会读取和执行~/.bash_logout
和/etc/bash.bash_logout
。 - non-login、interactive bash:即桌面环境下打开的虚拟终端使用的shell,会读取和执行
~/.bashrc
- non-login、non-interactive bash:即执行脚本用的bash,一般情况下不会读取文件。
图形界面登录使用就不是bash了,而是不知道哪款GUI shell了
建议自己的配置一般放入~/.bashrc
中
配置文件中会定义一些和用户使用相关的环境变量和shell变量,如PATH、命令提示符(prompt)、命令别名(alias)、权限掩码、默认编辑器等配置。
三 语法
3.1 简单命令
一条简单的bash命令,以要执行的命令开始,接着给出空格分隔的参数,最后以控制操作符结束,执行结束后,会返回一个状态码。执行一条命令类似于其他语言中调用一个函数。
不要将状态码和命令的标准输出混淆,状态码可以通过
$?
获得,bash中很多复合命令可以检查到命令放回的状态码而执行响应的动作。
一般状态码为0表示命令正常,其余非正常,但命令状态码的解释权归该命令所有。
其中控制操作符可以是&
,;
,换行
。以&
结束的命令语句,会在后台运行,bash不会等待命令的完成,而是直接执行下一条语句;以;
或换行
结束的命令语句,bash会顺序执行,等待其完成。
多条由管道、控制操作数、&&、|| 等符号隔开的命令序列称为list。执行list后,会返回list中最后一条被执行的命令的状态码。
3.2 复合命令
复合命令是bash提供的更为复杂的命令。书写命令时要注意符号间的空格
(list)
:list会在子shell环境中运行,因此list中的命令就算修改了环境变量,也不会影响当前shell的环境变量。为将要运行的程序添加环境变量而不影响当前shell的方式还有:
PATH=/usr/confusing:$PATH yourprogram
即命令前直接设置变量,此时也不会产生子shell。((expression))
:根据算法表达式expression计算的值返回对应的状态码。如果结果值不为零,状态码为0,否则返回1。[[ expression ]]
:根据条件表达式expression计算的值返回对应的状态码。如果表达式true,返回0,否则1。与[ expression ]
功能基本一致
关于表达式,可以使用逻辑运算符进行组合:
( expression )
:提升表达式执行的优先级! expression
:取反表达式的状态码expression1 && expression2
:两个表达式为true(状态码为0),才true。expression2不被执行,当且仅当expression1返回0(true)。expression1 || expression2
:任意一个表达式为true,则true。expression2被执行,当且仅当expression1返回1(false)
bash还提供了关于流程控制相关的命令:
for name in word ... ; do list ; done
name变量每次从in后取得一个值,然后运行一次list。word可使用通配符,自动被expansion(扩展)。for (( expr1 ; expr2 ; expr3 )) ; do list ; done
首先执行expr1,之后每次都检测expr2是否为0,如果为0则结束;否则执行list和expr3被执行,然后再重复检测。if list; then list; [ elif list; then list; ] ... [ else list; ] fi
如果list(不是表达式了)返回0,则执行then后的list,否则检查elif后的list,如果状态码都不为0,则执行else后的list。
其他的请查看man bash
手册。
3.3 字面值
shell只有一种类型,字符串。shell在执行命令之前,会查找变量、通配符、其他替换符号,然后替换,最终执行命令并传入处理过的参数。通过引号可以阻止这种行为:
- 无引号:shell会执行替换过程。多个参数空格分隔,不能出现单、双引号,可以用
\'
\"
替代。 - 单引号:引号内的所有字符不被替换且视为一个参数。但
'
不能出现在里面 - 双引号:与单引号类似,但里面的变量可被替换。
"
不能出现在里面
3.4 特殊变量
shell变量用于存储字面值、参与计算。bash为我们提供了一些特殊变量,用以获取相关的值,如当前shell的参数、进程号等等,但这些特殊变量不能被改变:
- 脚本参数:
$1,$2,...
运行脚本时传入的参数,$1对应第一个参数,$2对应第二个,等等。shift
可以删除第一个参数,其他参数前进补齐,即$2移入$1,$3移入$2,等等 - 参数个数:
$#
参数的个数,如果无则0 - 所有参数:
$@
一个包含所有参数的字符串 - 脚本名:
$0
- 进程ID:
$$
当前shell的进程号 - exit code:
$?
上一条命令的exit code。在脚本中,exit code一般为最后一条命令的exit code。也可以通过命令exit num
,手动返回exit code,并结束当前shell。如果num不给出,默认上一条命令的exit code
3.5 算术表达式
3.2小节提到了((expression))
可以计算算术表达式,下面给出所有的操作符:
id++
id--
variable post-increment and post-decrement++id
--id
variable pre-increment and pre-decrement-
+
unary minus and plus!
~
logical and bitwise negation**
exponentiation*
/
%
multiplication, division, remainder+
-
addition, subtraction<<
>>
left and right bitwise shifts<=
>=
comparison==
!=
equality and inequality&
bitwise AND^
bitwise exclusive OR|
bitwise OR&&
logical AND||
logical ORexpr?expr:expr
conditional operator=
*=
/=
%=
+=
-=
<<=
>>=
&=
^=
|=
assignmentexpr1 , expr2
comma
3.6 条件表达式
复合命令 [[ ]]
与bash内置[ ]
命令作用基本一致,可以进行文件测试、字符串测试、算术测试。部分功能与3.5小节重叠,具体参数参考man test
3.7 命令替换
${COMMAND}
允许命令的标准输出替换为命令行参数。如下面例子所示,echo 23
的输出23
替换了${echo 23}
[root@sidian Desktop]# echo 23
23
[root@sidian Desktop]# a=$(echo 23)
[root@sidian Desktop]# echo $a
23
3.8 算术替换
在使用((expression))
时,该复合命令只会返回状态码,没有标准输出输出结果,可以使用$((expression))
获得它的值。
[root@sidian Desktop]# a=$((23+3))
[root@sidian Desktop]# echo $a
26
当然可以不用算术替换,只用算术表达式
[root@sidian Desktop]# ((b=23+33))
[root@sidian Desktop]# echo $b
56
四 脚本
- 脚本就是bash命令的集合,并且脚本执行时开启了新的bash shell。
- 运行脚本前需要赋予它可执行权限。
- 运行脚本时,不明确给出脚本路径,则从PATH路径下查找
. script
或source script
会在当前shell中导入并执行脚本中的命令- bash脚本必须以
#!/bin/sh
作为首行。