本篇笔记基于 Bourne Again Shell (bash)。参考文章:(link).
1.启动与退出
bash # 启动 bash
exit # 退出 bash
2. echo
echo xx # 原样输出文本参数 XX
# 原样输出多行文本,单引号也可
echo "line1
line2
...
lineN"
默认情况下,echo 输出的文本末尾会有一个换行符。 -n 参数可以取消末尾的换行符。
echo a; echo b # 输出为两行,一行为 a,另一行为 b
echo -n a; echo b # 输出为 ab
默认情况下,引号中的特殊字符会被作为普通字符输出, -e 参数会解释特殊字符。
echo "Hello\nWorld" # 输出为一行字符
echo -e "Hello\nWorld" # 输出为两行字符
3.反斜杠 \
可通过反斜杠 \ 将较长的命令拆成多行,便于阅读。
echo -e "a\nb"
# 等价于
echo -e \
"a\nb"
4.空格
Bash 通过空格区分不同的参数。若参数之间有两个及以上的空格,则 Bash 只会解释一个空格。
echo a b # 输出为 a b
5.分号、&&、||
分号是命令的结束符,可用于在一行书写多个命令。
echo a ; echo b # 无论前一个命令是否被成功执行,下一个命令均会被执行。
echo a && echo b # 仅当前一个命令成功执行,下一个命令才会被执行。
echo a || echo b # 仅当前一个命令执行失败,下一个命令才会被执行。
6.type 命令
用于判断命令是内置命令,还是外部程序。
type echo
# 输出为 echo is a shell builtin
type ls
# 输出为 ls is hashed (/bin/ls)
7.自动补全
命令输入到一半的时候,可以按下 Tab 键,Bash 会自动完成剩下的部分。比如,输入tou,然后按一下 Tab 键,Bash 会自动补上ch。
除了命令的自动补全,Bash 还支持路径的自动补全。有时,需要输入很长的路径,这时只需要输入前面的部分,然后按下 Tab 键,就会自动补全后面的部分。如果有多个可能的选择,按两次 Tab 键,Bash 会显示所有选项,让你选择。
8.模式扩展(globbing)
Shell 接收到用户输入的命令以后,会根据空格将用户的输入拆分成一个个词元(token)。然后,Shell 会扩展词元里面的特殊字符,扩展完成后才会调用相应的命令。
Bash 是先进行扩展,再执行命令。命令本身并不存在参数扩展。
所有文件名扩展只匹配单层路径,不能跨目录匹配,即无法匹配子目录里面的文件。或者说,?或*这样的通配符,不能匹配路径分隔符(/)。
Bash 允许文件名使用通配符,即文件名包括特殊字符。这时引用文件名,需要把文件名放在单引号或双引号里面。
关闭扩展:
set -o noglob
set -f
打开扩展:
set +o noglob
set +f
波浪线扩展:
echo ~ # ~ 会被扩展为当前用户的主目录
cd ~/Desktop # ~/dir 会被扩展为主目录的子目录 dir
echo ~+ # ~+ 会被扩展为当前目录
? 字符扩展:? 匹配除空字符之外的任意单个字符,属于文件名扩展,可匹配文件或文件目录。
# 只有文件确实存在的前提下,才会发生扩展。
echo ?.txt
# 若当前目录有匹配文件 a.txt,则会输出 a.txt
# 若当前目录不存在匹配文件,则会输出 ?.txt
* 字符扩展:* 字符匹配文件路径中的任意数量的任意字符,包括零个字符、空字符。
# 存在文件 b.txt 和 ab.txt
ls *b*
# 输出 b.txt ab.txt
* 不会匹配隐藏文件(即以 . 开头的文件),要想匹配隐藏文件,需写成 .*
* 扩展同样属于文件名扩展,只有文件确实存在的前提下才会进行扩展。否则会原样输出。
* 扩展只匹配当前目录,不匹配子目录。
# 若子目录存在文件 a.txt
# 不会匹配子目录的文件
ls *.txt
# 可以匹配子目录的文件
ls */*.txt
方括号扩展:同样属于文件名扩展,只有文件确实存在的前提下才会进行扩展。否则会原样输出。
# [ab] 可以匹配 a 或 b
# 存在文件 a.txt 和 b.txt
ls [ab].txt
# 输出 a.txt b.txt
# [^...]、[!...] 表示匹配不在方括号里的字符
# 存在文件 aaa、bbb、aba
ls ?[!a]?
# 输出 bbb aba
如果需要匹配[字符,可以放在方括号内,比如[[aeiou]。如果需要匹配连字号-,只能放在方括号内部的开头或结尾,比如[-aeiou]或[aeiou-]。
[start-end]扩展表示匹配一个连续的范围。例如 [a-c] 等价于 [abc].
[!start-end]表示匹配不属于此范围的字符。
大括号扩展:分别扩展为大括号里的所有值。此扩展不属于文件名扩展,它会扩展成所有给定的值,而不管是否有对应的文件存在。
echo d{a,b,c}g
# 输出 dag dbg dcg
# 大括号中的逗号前后不能有空格,否则大括号扩展会失效
# 大括号中的某一项可以没有值,代表该项为空。但是该项仍会被扩展。
# 大括号扩展可以嵌套
# 大括号扩展可以与其他扩展连用,并且总是优先被扩展
{start..end}扩展表示扩展为一个连续序列,并且该扩展支持逆序,且可以嵌套使用。
echo {a..b}{1..3}
# 输出 a1 a2 a3 b1 b2 b3
变量扩展:Bash 将美元符号$开头的词元视为变量,将其扩展成变量值。变量名除了放在美元符号后面,也可以放在${}里面。${!string*}或${!string@}返回所有匹配给定字符串string的变量名。
子命令扩展:$(...)可以扩展成另一个命令的运行结果,该命令的所有输出都会被作为返回值。该扩展可以嵌套使用。
echo $(date)
# 2022年 7月17日 星期日 18时33分03秒 CST
echo `date`
# 具有相同效果
算术扩展:$((...))可以扩展成整数运算的结果。
echo $((2+2))
# 输出 4
量词语法:用于控制模式匹配的次数,只有在 Bash 的extglob参数打开的情况下才能使用。量词语法也属于文件名扩展,如果不存在可匹配的文件,就会原样输出。
shopt extglob # 用于查询当前参数是否被打开
shopt -s extglob # 打开 extglob 参数
?(pattern-list):模式匹配零次或一次。*(pattern-list):模式匹配零次或多次。+(pattern-list):模式匹配一次或多次。@(pattern-list):只匹配一次模式。!(pattern-list):匹配给定模式以外的任何内容。
ls abc?(.)txt # ?(.) 匹配零个或一个点
9.shopt 命令
# 打开某个参数
shopt -s [optionname]
# 关闭某个参数
shopt -u [optionname]
# 查询某个参数关闭还是打开
shopt [optionname]
dotglob参数可以让扩展结果包括隐藏文件(即点开头的文件)。默认情况下,扩展结果不包括隐藏文件。
nullglob参数在通配符不匹配任何文件名时,会让通配符返回空字符。默认情况下,通配符不匹配任何文件名时,会原样输出。
failglob参数在通配符不匹配任何文件名时,会让 Bash 直接报错,而不是让使用通配符的命令去处理匹配结果。
extglob参数使得 Bash 支持 ksh 的一些扩展语法,主要用于支持量词语法。
nocaseglob参数可以让通配符扩展不区分大小写。
globstar参数可以使得**匹配零个或多个子目录。
假设存在如下文件结构。顶层目录、第一级子目录sub1、第二级子目录sub1\sub2里面各有一个文本文件。
a.txt
sub1/b.txt
sub1/sub2/c.txt
使用通配符,查找出上述三个文件的方法:
ls *.txt */*.txt */*/*.txt
# 输出 a.txt sub1/b.txt sub1/sub2/c.txt
因为*只能匹配当前目录,如果要匹配子目录,只能一层层写出来。
打开globstar参数以后,使用**/*.txt就可以得到想要的结果。
shopt -s globstar
ls **/*.txt
# 输出 a.txt sub1/b.txt sub1/sub2/c.txt
10.sed 命令
sed -i '' "s/A/B/g" test.txt
sed -i '' "s/A/B/1" test.txt
#在 MAC 中,Shell 语句的换行符是 \n
sed -i '' "s/A/B \n C\g" test.txt
#需要对 / 进行转义
sed -i '' "s/A/'https:\/\/github.com'/g"
I)-i: 直接修改源文件。
II)g: 对数据中所有匹配到的内容进行替换。
III)n: 1~512 之间的数字,表示当要替换的字符串第 n 次出现时,才进行替换。
IV)'': 在 -i 之后加上一对引号,来指定备份格式。如果不需要备份,引号里的内容可以为空。