[TOC]
阮一峰老师写的教程,这里做个精简笔记。
1 Shell 简述
Shell 是一个程序、命令解释器、工具箱,目的是为了能让用户跟系统内核交互。
Shell 主要种类:
- Bourne Shell(sh)
- Bourne Again shell(bash)
- C Shell(csh)
- TENEX C Shell(tcsh)
- Korn shell(ksh)
- Z Shell(zsh)
- Friendly Interactive Shell(fish,这个不是 Mac 默认安装的,需要手动安装)
查看当前系统使用的 shell 、所有可用 shell、更改 shell。
1
2
3
$ echo $SHELL
$ cat /etc/shells
$ chsh -s /bin/xxx
2 命令参数格式和组合
Shell 使用空格(或 Tab 键)区分不同的参数,多余的空格会被忽略。
参数一般分为短参数和长参数两类,短参数多为单中划线+单个字母的形式 -x
,长参数多为双中划线+单词的形式 --word
。两类参数效果一样,短的常在人操作时使用,长的在脚本里用。
多条命令的执行:
- 用
;
进行分隔的命令,后续命令不会关注前边的命令是否执行成功,只要前边的命令执行完成,后续的命令就会执行 - 用
&&
或者||
进行连接的命令,具备短路效应
1
2
3
4
5
6
# 前后命令都会执行
$ cat filelist.txt ; ls -l filelist.txt
# 只有 cat 成功 才会执行 ls
$ cat filelist.txt && ls -l filelist.txt
# 只有 foo 没有创建成功才会创建 bar
$ mkdir foo || mkdir bar
3 模式扩展(globbing)
Shell 接收到命令和参数后,首先进行模式扩展和通配符扩展(wildcard expansion),然后再执行命令。扩展的结果是由 Bash 负责的,与所要执行的命令无关。命令本身并不存在参数扩展,收到什么参数就原样执行。
模式扩展与正则表达式的关系是,模式扩展早于正则表达式出现,可以看作是原始的正则表达式。它的功能没有正则那么强大灵活,但是优点是简单和方便。
Bash 有八种扩展:
~
字符扩展~
被扩展为当前用户目录~xxx
被扩展为用户 xxx 目录,如果用户不存在则不会扩展~+
被扩展为当前目录,等价于pwd
?
字符扩展?
是文件名扩展,如果文件不存在则不进行扩展,其匹配任意单个非空字符。1 2 3 4 5 6 7
# 当前目录有 a.txt 文件,进行扩展 $ echo ?.txt a.txt # 当前目录为空目录,不进行扩展 $ echo ?.txt ?.txt
*
字符扩展*
是文件名扩展匹配任意字符包括空字符。方括号扩展
方括号扩展是文件名扩展,文件存在时才会扩展。
[...]
,匹配其中任意一个字符[^...]
和[!...]
,匹配不在其中的字符[start-end]
,起始写法[!start-end]
,起始写法
大括号扩展
大括号扩展不是文件名扩展,它总会扩展成所有给定的值,而不管是否有对应的文件存在。
大括号扩展
{...}
表示分别扩展成大括号里面的所有值,各个值之间使用逗号分隔。比如,{1,2,3}
扩展成1 2 3
。1 2 3 4 5 6 7
$ echo {1,2,3} 1 2 3 $ echo d{a,e,i,u,o}g dag deg dig dug dog $ echo Front-{A,B,C}-Back Front-A-Back Front-B-Back Front-C-Back
逗号前后有空格,Bash 就会认为这不是大括号扩展,而是三个独立的参数。
1 2
$ echo {1 , 2} {1 , 2}
逗号前面可以没有值,表示扩展的第一项为空。
1 2
$ echo a.log{,.bak} a.log a.log.bak
可以嵌套。
1 2 3 4 5
$ echo {j{p,pe}g,png} jpg jpeg png $ echo a{A{1,2},B{3,4}}b aA1b aA2b aB3b aB4b
大括号也可以与其他模式联用,并且总是先于其他模式进行扩展。
1 2 3 4 5 6
# 先进行大括号扩展,然后进行*扩展,等同于执行两条echo命令 $ echo /bin/{cat,b*} /bin/cat /bin/b2sum /bin/base32 /bin/base64 ... ... # 等同于 $ echo /bin/cat;echo /bin/b*
{start..end}
,起始写法{start..end..step}
,带间隔的起始写法
变量扩展
$
开头或者${xxx}
视为变量,将其扩展成变量值。子命令扩展
$(...)
可以扩展成另一个命令的运行结果,该命令的所有输出都会作为返回值。老的语法,子命令放在反引号之中,也可以扩展成命令的运行结果。1 2 3 4
$ echo $(date) Tue Jan 28 00:01:13 CST 2020 $ echo `date` Tue Jan 28 00:01:13 CST 2020
$(...)
也可以嵌套,比如$(ls $(pwd))
。
算术扩展
$((...))
可以扩展成整数运算的结果。
3.1 字符类
[[:class:]]
表示一个字符类,扩展成某一类特定字符之中的一个。常用的字符类如下。
[[:alnum:]]
:匹配任意英文字母与数字[[:alpha:]]
:匹配任意英文字母[[:blank:]]
:空格和 Tab 键[[:cntrl:]]
:ASCII 码 0-31 的不可打印字符[[:digit:]]
:匹配任意数字 0-9[[:graph:]]
:A-Z、a-z、0-9 和标点符号[[:lower:]]
:匹配任意小写字母 a-z[[:print:]]
:ASCII 码 32-127 的可打印字符[[:punct:]]
:标点符号(除了 A-Z、a-z、0-9 的可打印字符)[[:space:]]
:空格、Tab、LF(10)、VT(11)、FF(12)、CR(13)[[:upper:]]
:匹配任意大写字母 A-Z[[:xdigit:]]
:16进制字符(A-F、a-f、0-9)
3.2 量词语法
量词语法用来控制模式匹配的次数。它只有在 Bash 的extglob
参数打开的情况下才能使用,不过一般是默认打开的。
?(pattern-list)
:匹配零个或一个模式。*(pattern-list)
:匹配零个或多个模式。+(pattern-list)
:匹配一个或多个模式。@(pattern-list)
:只匹配一个模式。!(pattern-list)
:匹配给定模式以外的任何内容。
4 echo 命令
echo
命令把跟在其后的输入原样输出出来。
1
2
$ echo hello world
hello world
内容放在引号内可以多行输出
1
2
$ echo "hello
world"
4.1 参数
- -n 去掉末尾换行
1
2
$ echo -n hello world
hello world$
- -e 解释引号内特殊字符(zsh 没有此参数,默认会解释特殊字符)
1
2
3
4
5
6
$ echo "Hello\nWorld"
Hello\nWorld
$ echo -e "Hello\nWorld"
Hello
World
5 type 命令
type
用来判断命令的类型,内置命令还是外部程序。
1
2
3
4
$ type echo
echo is a shell builtin
$ type ls
ls is hashed (/bin/ls)
-t 参数返回命令类型,别名(alias),关键词(keyword),函数(function),内置命令(builtin)和文件(file)。
6 标准输入、输出、错误重定向
在 shell 中每个进程都与三个系统文件相关联:标准输入 stdin、标准输出 stdout、标准错误 stderr,三个系统文件的文件描述符分别为0、1、2。因此有时遇到重定向时,需要根据数字进行判断。譬如:
2>&1
表示将标准错误重定向到标准输出xxx 2 > /dev/null
表示丢弃标准错误
License:署名-相同方式共享 3.0