前言
虽然一直都在用,但有些命令仍是半知半懂的,所以就好好学一下吧。
一些辅助工具:
- shellcheck - Shell 脚本静态检查工具,主流编辑器都有插件。类似 ESLint 的工具。
- zx - Google 出品,用 JavaScript 写 Shell 脚本。
本文大部分内容来自阮一峰老师的 Bash 脚本教程。
一、Shell 命令格式
$ command [ arg1 ... [ argN ] ]
其中 command
是一个具体的命令或者一个可执行文件,arg1... argN
是传递给命令的参数,是可选的。
命令与参数,参数与参数之间通过「一个空格」隔开。若有「多个空格」,多余空格会被自动忽略,作用相当于一个空格。
$ ls -l
其中 ls
是命令,-l
是参数。有些参数是命令的配置项,它们一般以一个「短横线」开头,比如上面的 -l
。通常配置项参数有短形式和长形式两种形式,比如 -l
是短形式,--list
是长形式。两种写法作用完全相同,短形式便于输入,长形式可读性、语义更好。
通常命令都是一行的,可有些命令较长,写成多行有利于阅读和编辑,只要在每行结尾处加上反斜杠 \
可以,Shell 会将下一行跟当前行一起解析。
$ echo Hello World
# 等同于
$ echo Hello \
World
二、命令的组合与继发
命令组合符 &&
,前一个命令执行成功,才会接着执行第二个命令。
$ command1 && command2
命令组合符 ||
,前一个命令执行失败,才会接着执行第二个命令。
$ command1 || command2
命令结束符 ;
(分号),前一个命令执行结束后(无论成功与否),接着执行第二个命令。命令结束符可使得一行中放置多个命令。
$ clear; ls
管道符 |
,前一个命令的输出作为第二个命令的输入。
$ command1 | command2
三、引号
- 单引号:单引号用于保留字符的字面含义,各种特殊字符在单引号里面,都会变为普通字符。
- 双引号:比单引号宽松,大部分特殊字符在双引号里面,都会失去特殊含义,变成普通字符。但是,三个特殊字符除外:美元符号(
$
)、反引号(`
)和反斜杠(\
)。这三个字符在双引号之中,依然有特殊含义,会被 Bash 自动扩展。
$ echo '$USER'
$USER
$ echo "$USER"
frankie
换行符在双引号之中,会失去特殊含义,Bash 不再将其解释为命令的结束,只是作为普通的换行符。所以可以利用双引号,在命令行输入多行文本。
$ echo "hello
world"
hello
world
echo
发音 [ˈekō](才发现原来一直读错了,惭愧)。其参数 -e
会解析引号中的特殊字符(比如换行符 \n
)。若在 CLI 中直接输入 echo
命令 \n
也会解析为换行符,而不是普通的 \n
字符串。
$ echo -e "Hello\nShell"
Hello
Shell
四、子命令扩展
$(...)
可以扩展成另一个命令的运行结果,该命令的所有输出都会作为返回值。还有另一种较老的语法,子命令放在反引号之中,也可以扩展成命令的运行结果。
$ echo $(date)
2022年 6月27日 星期一 00时31分14秒 CST
$ echo `date`
2022年 6月27日 星期一 00时32分01秒 CST
五、读取变量
- 在变量名前加上
$
,比如$SHELL
。 - 读取变量时,变量名可以使用花括号
{}
包围,比如$SHELL
可以写成${SHELL}
。 - 如果变量的值本身也是变量,可以使用
${!varname}
语法,读取最终的值。(好像不太对,待进一步验证)
六、算术运算
- 除法运算符的返回结果总是为「整数」,比如
$(( 5 / 2 ))
的结果为2
,而不是2.5
。 -
$(( ... ))
的圆括号之中,不需要在变量名之前加上$
,不过加上也不报错。 - 如果
$((...))
里面使用不存在的变量,也会当作0
处理。 -
$[...]
是以前的语法,也可以做整数运算,不建议使用。
小数运算,需借助 bc
命令,其中 scale
表示小数位,ibase
和 obase
进行其他进制数运算。比如:
$ var1=3
$ var2=6
$ result=$(echo "scale=2; $var1 / $var2" | bc)
$ echo $result
.50
七、目录堆栈
cd -
命令可以返回前一次的目录。默认情况下,只记录上一次所在的目录。
$ cd ~/Desktop/
$ cd -
~
八、脚本
8.1 Shebang 行
脚本的第一行通常是指定解释器,即这个脚本必须通过什么解释器执行。这一行以 #!
字符开头,这个字符称为 Shebang,所以这一行就叫做 Shebang 行。
#!
后面就是脚本解释器的位置,Bash 脚本的解释器一般是 /bin/sh
或 /bin/bash
。
#!/bin/sh
# 或者
#!/bin/bash
#!
与脚本解释器之间有没有空格,都是可以的。
如果 Bash 解释器不放在目录 /bin
,脚本就无法执行了。为了保险,可以写成下面这样。
#!/usr/bin/env bash
上面命令使用 env
命令(这个命令总是在 /usr/bin
目录),返回 Bash 可执行文件的位置。env
命令的详细介绍,请看后文。
Shebang 行不是必需的,但是建议加上这行。如果缺少该行,就需要手动将脚本传给解释器。
举例来说,脚本是 script.sh
,有 Shebang 行的时候,可以直接调用执行。
$ ./script.sh
上面例子中,script.sh
是脚本文件名。脚本通常使用 .sh
后缀名,不过这不是必需的。
如果没有 Shebang 行,就只能手动将脚本传给解释器来执行。
$ /bin/sh ./script.sh
# 或者
$ bash ./script.sh
8.2 执行权限和路径
前面说过,只要指定了 Shebang 行的脚本,可以直接执行。这有一个前提条件,就是脚本需要有执行权限。可以使用下面的命令,赋予脚本执行权限。
给所有用户执行权限
$ chmod +x script.sh
给所有用户读权限和执行权限
$ chmod +rx script.sh
# 或者
$ chmod 755 script.sh
只给脚本拥有者读权限和执行权限
$ chmod u+rx script.sh
脚本的权限通常设为 755
(拥有者有所有权限,其他人有读和执行权限)或者 700
(只有拥有者可以执行)。
除了执行权限,脚本调用时,一般需要指定脚本的路径(比如 path/script.sh
)。如果将脚本放在环境变量 $PATH
指定的目录中,就不需要指定路径了。因为 Bash 会自动到这些目录中,寻找是否存在同名的可执行文件。
建议在主目录新建一个 ~/bin
子目录,专门存放可执行脚本,然后把 ~/bin
加入 $PATH
。
export PATH=$PATH:~/bin
上面命令改变环境变量 $PATH
,将 ~/bin
添加到 $PATH
的末尾。可以将这一行加到 ~/.zshrc
文件里面,然后重新加载一次 .zshrc
,这个配置就可以生效了。
$ source ~/.zshrc
以后不管在什么目录,直接输入脚本文件名,脚本就会执行。
$ script.sh
上面命令没有指定脚本路径,因为 script.sh
在 $PATH
指定的目录中。
上面的配置文件,取决于你当前所用的 Shell。比如我这里是 zsh,配置文件为
~/.zshrc
,如果你是 bash,可能是~/.bash_profile
、~/.bashrc
等。
未完待续...
网友评论