Bash 是遵循 Bournes Shell 标准的代表,市面上大部分的 Shell 都遵循 Bournes Shell 标准,以 Bash 为例学习如何使用 Shell 构建脚本。
温馨提示:文章内容受限于笔者的认知,如有错误请指出
什么是 Bash
名称来源
Bash(Bourne-Again SHell)它是 Borune shell(简称为 sh) 的后继兼容版本与开放源代码版本,其名称来源于一个双关语 Born(Bourne) Again,译作『重生』。1
Shell 是什么
Shell(也称为壳层)在计算机科学中指『为用户提供用户界面』的软件,通常指的是『命令行界面』的『解析器』。
所以 Shell 本质是一个解析用户命令的软件,下图为 Bash 的截图。1
不同平台使用的 Shell
在 Windows 平台下有 PowerShell,MacOS 有 Zsh(Z Shell),而 Linux 中有 Bash(这里只列举了各平台中常见的,并不代表只使用这些)。
他们虽然名称不同但都是 Shell 的分支,只不过提供了更多的特性,比如 Zsh 中的自动补全和命令别名等,这些特性知识让用户使用命令行更加的方便,但是本质上都是『解析用户命令的软件』。
Bash 登场
Bash 是 Unix Shell(运行在 Unix 操作系统上的 Shell)的一种。1
Bash 同上文提到的 Zsh 一样,多了许多的特性,但本质不变,后续将会介绍这里不再赘述。
Hello Bash
Windows 平台使用遵循 Bourne Shell 标准的 Shell
可以尝试安装 WSL(Windows Subsystem for Linux)使用 Linux 系统以使用遵循 Bourne Shell 标准的 Shell,具体教程可以查看 Microsoft 提供的安装 WSL 教程。
检查 Shell
在命令行界面输入 echo $SHELL
以查看使用的 Shell 程序是否满足要求,若输出为 ../bash
或 ../zsh
则满足。
说你好
$ echo hello\ world
hello world
$
这是一个简单的命令行界面,第一行的内容中有美元符号$
、echo
命令和 hello\ world
参数;
$
代表了当前用户不是 root
用户(后续会进行介绍,可以视为超级管理员可以做任何操作不受限制),而代表 root
用户的符号为井字符 #
。
echo
译作『回响』,即将输入的参数部分显示在屏幕上(即第二行的内容)。
hello\ world
中反斜杠 “ 为转义符,即告知 hello world
中间需要有空格保留,而不是作为 hello
和 world
两个参数进行输入。也可以用英文半角双引号 ""
将内容扩起,同样表示一个参数,如 echo "hello world"
。
潜规则
在进入到下一小节之前需要了解一个交互的潜规则——成功无响应,而失败则报错。
比如执行删除命令 rm
,其中删除的是一个文件夹:
$ rm dir
rm: dir: is a directory
$
rm
程序会告知你 dir
是个文件夹。
它没有明显的错误标识,但是如果执行指令时出现了信息提示就代表该命令失败了。
注意
信息提示不是输出结果,如上文
echo
的例子,为输出结果,你可以仔细比较两者的区别。
echo 命令的执行
Bash 通过环境变量 PATH
查找名为 echo
的可执行二进制文件,找到并运行它同时将参数输入进 echo
程序中。
环境变量 PATH
环境变量(Environment Variables)是计算机操作系统中的一种机制,用于存储系统和应用程序运行时所需的配置信息,配置信息以键值对的方式存在。简单而言,在程序运行之前系统就会将这些名为环境变量的变量就已经被分配好了,无需在程序内再次定义,在程序运行时也可以直接获取使用。
可以通过 echo
命令来显示 PATH
变量
$ echo $PATH
/usr/bin:/usr/local/bin
$
PATH
前的美元符号 $
是一个标识符,告诉 Bash PATH
是一个变量需要引用并替换。
在第二行可以看到会有许多目录地址,以冒号 :
作为分隔符来区分不同的目录地址。
Path 译作路径,PATH
变量也就是 Bash 用来寻找命令对应的程序文件(即同名的可执行二进制文件)的『地图』,如果输入的命令在这份『地图』里找不到,就会提示 command not found
错误,这时候你应该添加相应的路径帮助 Bash 找到命令所对应的程序文件,如 export PATH=/usr/bin
,这样就将 /usr/bin
添加到 PATH
变量中了,该路径底下所有的可执行二进制文件都可以通过输入文件名称在 Bash 中运行。
命令的使用方法
echo
等许多其他常见的命令都是系统内建(built-in)的,通常位于 /usr/bin
目录下。
小知识
bin 是 binary 的缩写,binary 指二进制文件。
bin 文件夹下通常都存放着可执行二进制文件,在类 Unix 平台(如 Linux 和 MacOS)中这类文件通常没有扩展名(如 a.txt,这里的 .txt 就是扩展名),而 Winodws 平台下可执行二进制文件的扩展名为
.exe
。
更多命令可以查看菜鸟教程,你也可以通过 man <命令名称>
来查看使用手册(manual),按『q 键』以退出查看,上下方向键以滚动。
手册中用方括号 []
扩起的内容代表『可选(optional)』
$ man ls
NAME
ls – list directory contents
SYNOPSIS
ls [-@ABCFGHILOPRSTUWabcdefghiklmnopqrstuvwxy1%,] [--color=when]
[-D format] [file ...]
# ...
:
但是 man
指令对于了解如何使用一个不太熟悉的指令往往是不直观的,因为它所显示的页面类似于文档或者技术手册,并不能直接告诉我们遇到什么情况使用哪些可选的参数,比如 tar
指令,这是解压或压缩特定文件时经常用到的指令,它一共用 5 个可选参数 -c, -r, -t, -u, -x
,并且之间可以组合以实现不同的效果。这种情况我们往往需要鲜明的例子来快速掌握遇到何种情况使用哪些组合,而不是花费大量时间查看手册结果最后也不知所以。
tldr 是一个很好的工具,他通过例子的方式告诉我们如何使用不熟悉的指令,比如刚才提到的 tar
。
$ tldr tar
tar
Archiving utility.
Often combined with a compression method, such as gzip or bzip2.
More information: <https://www.gnu.org/software/tar>.
- [c]reate an archive and write it to a [f]ile:
tar cf path/to/target.tar path/to/file1 path/to/file2 ...
- [c]reate a g[z]ipped archive and write it to a [f]ile:
tar czf path/to/target.tar.gz path/to/file1 path/to/file2 ...
# .. and more
$
非常的直观和方便,如果你不会使用 tldr
当然也可以使用 tldr tldr
来获得帮助。
流的重定向
输入和输出流
输入流(input stream)在 Bash 中用小于号表示 < 文件名
,它将文件作为标准输入
输出流(output stream)用大于号表示 > 文件名
,它将标准输出输入在目标文件中,如果不存在会自动创建否则会覆盖原内容,如果要避免覆盖目标文件则需要使用两个大于号 >>
表示追加。
流是一种抽象的形态,输入和输出是一个连续的过程,就像打字一般,需要将拼音一个一个键入才能让输入法显示出相应的文字,这种一个一个键入的感觉就像水流一样,有序且连续。
标准输入(stdin)标准输入是指输入至程序的资料,这通常是文件,而在命令行界面输入的预期是键盘键入的参数,如 echo hi
中的 hi
标准输出(stdout)是指程序写输出资料的流,这通常直接输入在终端(Terminal)页面,如 echo hello
执行后显示的 hello
,除非进行重定向比如使用 > 文件名
将输出输入至目标文件里。终端通常指我们看到的命令行界面。
$ echo hello/ world > hello.txt
$ cat < hello.txt
hello world
$
在执行第一行后屏幕上并没有输出,这是因为 Bash 通过将输出流给导入进 hello.txt
文件中,而第二行则是将 hello.txt
文件作为标准输入(不是文件中的内容)给 cat
作为参数(cat
命令用于打印文件内容和连接文件),所以会在第三行中显示。
注意
一些指令是不支持重定向输入流作为标准输入(包括下文提到的『管道』),他们只接受键盘键入的参数作为标准输入,比如
echo
和cd
,具体解决办法需要查看tool&script.md
。
管道
管道(Pipe)在 Bash 中以竖线符号 |
表示。在 |
左侧作为管道的输入,在其右侧作为管道的输出。
可以从图中清楚的看到管道的作用,就是将竖线符号 |
左侧命令的输出作为其右侧命令的参数输入,最后将右侧命令的输出显示在屏幕上,当然你可以使用大于号 >
或两个大于号 >>
改变其输出的目标。
$ ls | tail -n1
last # ...
$
ls
表示显示当前目录下所有文件或文件夹的名称。
tail
表示输出输入参数尾部的信息,-n1
是表示尾部第一行,也就是显示 ls
命令输出中的倒数第一行的文件或文件夹的名称。
注意
竖线符号
|
的左右两侧分别是两个命令,比方执行sudo ls | rm -r
,第二条rm
命令是不具有sudo
程序运行后所赋予的权限的,若是无权删除的文件或文件夹则会运行失败并报错。