这篇文章是《Linux命令行大全》的阅读笔记,仅供参考,更多详细内容请参见该书。

1.符号链接

  • 软链接(item可以是一个文件或目录)

    1
    $ ln -s item link

一个符号链接指向一个文件,而且这个符号链接本身与其它的符号链接几乎没有区别。例如,如果我们往一个符号链接里面写入东西,那么相关联的文件也被写入。然而,当删除一个符号链接时,只有这个链接被删除,而不是文件自身。如果先于符号链接删除文件,这个链接仍然存在,但是不指向任何东西。在这种情况下,这个链接被称为坏链接

符号链接文件的长度是目标文件字符串所包含的字符数,而不是符号链接所指向的文件长度

链接所指向的文件长度

  • 硬链接(一个文件至少有一个硬链接)

    1
    $ ln file link
  • 硬链接的局限性

    • 一个硬链接不能关联它所在文件系统之外的文件,也就是说一个链接不能关联与链接本身不在同一个磁盘分区上的文件(不同的物理磁盘)
    • 一个硬链接不能关联一个目录

一个硬链接和文件本身没有什么区别。不像符号链接,当你列出一个包含硬链接的目录内容时,你会看到没有特殊的链接指示说明。当一个硬链接被删除时,这个链接被删除,但是文件本身的内容仍然存在(即它所占的磁盘空间不会被重新分配),直到所有关联这个文件的链接都删除掉

假设文件由两部分组成:包含文件内容的数据部分和持有文件名的名字部分,当我们创建文件硬链接的时候,实际上是为文件创建了额外的名字部分,并且这些名字都关联到相同的数据部分。这时系统会分配一连串的磁盘块给所谓的索引节点,然后索引节点与文件名字部分相关联。因此每一个硬链接都关系到一个具体的包含文件内容的索引节点(ls -li显示文件索引节点信息)

在 GNOME 里面,当拖动文件时,同时按下 Ctrl+Shift 按键会创建一个链接,而不是复制(或移动)文件。在 KDE 中,无论什么时候放下一个文件,会弹出一个小菜单,这个菜单会提供复制,移动,或创建链接文件选项

2.shell的通配符

通配符 含义
* 匹配任意多个字符
? 匹配任意一个字符
[characters] 匹配任意一个属于字符集中的字符
[!characters] 匹配任意一个不是字符集中的字符
[[:class:]] 匹配任意一个属于指定字符类中的字符
  • 最常用字符类
字符类 含义
[:alnum:] 匹配任意一个字母或数字
[:alpha:] 匹配任意一个字母
[:gidit:] 匹配任意一个数字
[:lower:] 匹配任意一个小写字母
[:upper:] 匹配任意一个大写字母

g*:文件名以g开头的文件

[abc]*:文件名以a,b或c开头的文件

*[[:lower:]123]:文件名以小写字母或以1,2或3结尾的文件

注意表示法**:** 在描述一个命令时,当有三个圆点跟在一个命令的参数后面,这意味着那个参数可以重复

3.命令

命令 作用
type 显示命令类型
which 显示可执行程序的位置(不包括内建)
help 显示shell内建命令帮助文档
–help 显示用法信息
man 显示程序手册页
apropos 显示适当的命令
whatis 显示非常简洁的命令说明
info 显示程序的info页
alias 创建我们自己的命令
  • alias name='string':给命令创建别名 unalias:删除别名

  • 要查看所有定义在系统环境中的别名,使用不带参数的 alias 命令

  • 命令行小技巧:把多个命令放在同一行上,命令之间用;分开

  • 相关命令

命令 作用
cat 连接文件
sort 排序文本行
uniq 报道或省略重复行
grep 打印匹配行
wc 打印文件中换行符、字和字节个数
head 输出文件的第一部分(默认10行)
tail 输出文件的最后一部分(默认10行)
tee 从标准输入读取数据并同时写到标准输出和文件

4.重定向

  • 标准输入(stdin) 标准输入重定向<
  • 标准输出(stdout) 标准输出重定向>/>>>表示开头重写文件 >>表示追加重定向结果到文件内容之后
  • 标准错误(stderr) 标准错误重定向

当我们使用>重定向符来重定向输出结果时,目标文件总是从开头被重写。若ls命令没有产生运行结果,只有错误信息,重定向操作开始重写文件,然后由于错误而停止,导致文件内容清空。事实上,如果我们需要清空一个文件内容(或者创建一个新的空文件),可以使用这样的技巧:> ls-output,txt

标准错误重定向没有专用的重定向操作符。为了重定向标准错误,我们必须参考其文件描述符。虽然我们已经将这些文件流的前三个称作标准输入、输出和错误,shell 内部分别将其称为文件描述符 0、1 和 2。shell 使用文件描述符提供了一种表示法来重定向文件。因为标准错误被称为文件描述符 2,因此可以用这种表示法来重定向标准错误,例如:ls -l /bin/usr 2> ls-error.txt,其中文件描述符2,紧挨着放在重定向操作符之前,来执行重定向标准错误到文件的任务

重定向标准输出和错误到同一文件:

  • 传统方法(旧版bash):ls -l /bin/usr > ls-output.txt 2>&1

    首先重定向标准输出到文件 ls-output.txt,然后重定向文件描述符 2(标准错误)到文件描述符 1(标准输出)使用表示法 2>&1,注意重定向的顺序安排非常重要。标准错误的重定向必须总是出现在标准输出重定向之后,要不然它不起作用

  • 现代方法(新版bash): ls -l /bin/usr &> ls-output.txt

  • 管道线

命令从标准输入读取数据并输送到标准输出的能力被一个称为管道线的 shell 特性所利用。使用管道操作符 “|”(竖杠),一个命令的标准输出可以通过管道送至另一个命令的标准输入

1
$ command1 | command2

有时有可能会把几个命令放在一起组成一个管道线。通常,以这种方式使用的命令被称为过滤器

uniq 命令经常和 sort 命令结合在一起使用。uniq 从标准输入或单个文件名参数接受数据有序列表,默认情况下,从数据列表中删除任何重复行

5.echo

  • 字符展开

每当我们输入一个命令并按下 enter 键,bash 会在执行你的命令之前对输入的字符完成几个步骤的处理。这背后的过程叫做(字符)展开。通过展开,我们输入的字符,在 shell 对它起作用之前,会展开成为别的字符

波浪线字符 () 有特殊的含义。当它用在一个单词的开头时(没有空格),它会展开成指定用户的家目录名,如果没有指定用户名,则展开成当前用户的家目录

  • 算术表达式展开

格式:$((expression))

算术表达式只支持整数(全部是数字,不带小数点),在算术表达式中空格并不重要,并且表达式可以嵌套

  • 花括号展开

从一个包含花括号的模式中创建多个文本字符串,花括号表达式本身可能包含一个由逗号分开的字符串列表,或者一个整数区间,或者单个的字符的区间。这种模式不能嵌入空白字符

1
2
3
4
5
6
$ echo Front-{A,B,C}-Back
Front-A-Back Front-B-Back Front-C-Back
$ echo Number_{1..5}
Number_1 Number_2 Number_3 Number_4 Number_5
$ echo a{A{1,2},B{3,4}}b
aA1b aA2b aB3b aB4b
1
2
3
4
5
6
# 查看有效的变量列表
$ printenv | less
# 命令替换
$ echo $(ls) # 把一个命令的输出作为一个展开模式来使用
# 在旧版 shell 程序中,bash 也支持命令替换。它使用倒引号来代替美元符号和括号
$ echo `ls`

shell 提供了一种叫做引用的机制,来有选择地禁止不需要的展开

  • 双引号

把文本放在双引号中,shell 使用的特殊字符,都失去它们的特殊含义,被当作普通字符来看待。有几个例外:$、\ (反斜杠)和 `(倒引号),但参数展开、算术展开和命令替换仍然执行

在默认情况下,单词分割机制会在单词中寻找空格,制表符,和换行符,并把它们看作单词之间的界定符。这意味着无引用的空格,制表符和换行符都不是文本的一部分,它们只作为分隔符使用;但加上双引号,单词分割被禁止,内嵌空格也不会被当做界定符

  • 单引号

如果需要禁止所有的展开,我们要使用单引号

  • 转义字符

阻止单个字符的展开

echo命令带上-e选项,能够解释转义序列,若不用-e选项则把转义序列放在$''中也能解释转义序列

6.键盘高级操作技巧

  • 移动光标
按键 作用
Ctrl-d 删除光标位置的字符
Ctrl-e 移动光标到行尾
Ctrl-f 光标前移一个字符,和左箭头作用一样
Ctrl-b 光标后移一个字符,和右箭头作用一样
Alt-f 光标前移一个字
Alt-b 光标后移一个字
Ctrl-l 清空屏幕并移动光标到左上角,与clear作用相同
  • 修改文本
按键 作用
Ctrl-a 移动光标到行首
Ctrl-t 光标位置字符和光标前面字符互换
Alt-t 光标位置的字和其前面的字互换位置
Alt-l 把从光标位置到字尾的字符转换为小写字母
Alt-u 把从光标位置到字尾的字符转换为大写字母
  • 剪切/粘贴文本

Readline 的文档使用术语 killing 和 yanking 来指我们平常所说的剪切和粘贴。剪切下来的本文被存储在一个叫做剪切环 (kill-ring) 的缓冲区中

按键 作用
Ctrl-k 剪切从光标位置到行尾的文本
Ctrl-u 剪切从光标位置到行首的文本
Alt-d 剪切从光标位置到词尾的文本
Alt-Backspace 剪切从光标位置到词头的文本。如果光标在一个单词的开头,剪切前一个单词
Ctrl-y 把剪切环中的文本粘贴到光标位置

历史命令展开:!88:bash会把!88展开成为历史列表中88行的内容

!!:重复最后一次执行的命令

!number :重复历史列表中第 number 行的命令

!string:重复最近历史列表中,以这个字符串开头的命令

!?string:重复最近历史列表中,包含这个字符串的命令

7.权限

  • 拥有者、组成员和其他人

-rw-rw-r--:文件所有者(rw-)、文件组所有者(rw-)和其他人(r–)的读、写和执行权限

掩码:掩码的二进制形式中,出现数字 1 的位置,相应地关掉一个文件模式属性 umask设置默认权限

权限属性:(w属性是针对内容的修改,不过,对于文件来说,w属性指是否可以修改文件中的内容;而对于目录来说,w属性指是否可以修改目录下的文件本身而不是其中的内容)

其他特殊权限参照《Linux命令行大全》P112

属性 文件 目录
r 允许打开并读取文件内容 允许列出目录内容(前提是目录具有可执行属性)
w 允许写入/截断文件,但不允许对文件进行重命名或删除操作 允许在目录下新建、删除或重命名文件(前提是目录具有可执行属性)
x 运行程序(前提是该文件可读) 允许进入目录
  • su -:启动超级用户的shell
  • sudo命令不要求超级用户的密码而是使用当前用户的密码来认证

su 和 sudo 之间的一个重要区别是 sudo 不会重新启动一个 shell,也不会加载另一个用户的 shell 运行环境,需要执行的命令也不需要用单引号引起来

  • chown
参数 结果
thee 把文件所有者从当前属主更改为用户thee
thee:users 把文件所有者改为用户 thee,文件用户组改为用户组 users
:admins 把文件用户组改为组 admins,文件所有者不变
thee: 文件所有者改为用户 thee,文件用户组改为用户 thee 登录系统时所属的用户组

练习:如何设置一个共享目录(参见《Linux命令行大全》P117)

  • passwd
1
$ passwd [user]

8.进程

1
2
3
4
5
6
7
8
9
10
11
#  ps 命令能够展示许多计算机运行状态的信息,但是它只是提供 ps 命令执行时刻的机器状态快照
$ ps x # 展示所有进程
$ ps aux # 展示所有进程的更多信息
# top 程序以进程活动顺序显示连续更新的系统进程列表
# 一个在后台运行的进程对一切来自键盘的输入都免疫,也不能用 Ctrl-c 来中断它
# Ctrl-z,可以停止一个前台进程(不是终止进程)
# jobs 可以列出从终端中启动了的任务的方法
$ jobs
# fg将进程返回到前台 bg把程序移动到后台
$ fg %1
# fg 命令之后,跟随着一个百分号和任务序号(叫做 jobspec, 如此处的%1)就可以了。如果我们只有一个后台任务,那么 jobspec(job specification) 是可有可无的

使用 Ctrl-c 的情况下,会发送一个叫做 INT(Interrupt, 中断)的信号;当使用 Ctrl-z 时,则发送一个叫做 TSTP(Terminal Stop, 终端停止)的信号

可以通过kill命令来给程序发送信号,常见信号参见《Linux命令行大全》P131

kill -l可以得到一个完整的信号列表,killall命令,可以给匹配特定程序或用户名的多个进程发送信号

  • 正常来说,我们对于文件.bashrc 的修改不会生效,直到关闭终端会话,再重新启动一个新的会话,因为.bashrc 文件只是在刚开始启动终端会话时读取,但是可以通过执行source .bashrc来强制激活修改

9.vi/vim

  • 移动光标:参见《Linux命令行大全》P151
  • 删除文本:参见《Linux命令行大全》P154
  • 剪切、复制和粘贴文本:参见《Linux命令行大全》P155
  • 文件间切换ex命令::n切换下一个文件 :N返回先前的文件
  • 多文件操作::buffers显示文件列表 :buffer 2切换文件缓冲区 :e new.txt打开(新建)文件并编辑
  • 插入整个文件内容到其他文件中::r new.txt(把new.txt文件插入到光标位置之前)
  • 保存文件:ex命令:w 命令模式下的ZZ(保存并退出文件) ex命令:wq(保存并退出) ex命令:w filename.txt(另存为filename.txt但不会更改当前的文件为filename.txt)
命令按键 作用
u 命令模式下,撤销最后一次修改
i 命令模式下,插入文本
a 命令模式下,进入插入模式且光标后移一个字符
A 光标移动到行尾,同时进入插入模式
o 在当前行的下方插入一个空白行且进入到插入模式
O 在当前行的上方插入一个空白行且进入到插入模式
dd 删除光标所在的当前行

10.软件包管理

  • 查找资源库中的软件包
风格 命令
Debian apt-get update; apt-cache search search_string
Red Hat yum search search_string
  • 安装资源库中的软件包
风格 命令
Debian apt-get update; apt-get install package_name
Red Hat yum install package_name
  • 通过软件包文件安装软件(非资源库)
风格 命令
Debian dpkg –install package_file
Red Hat rpm -i package_file
  • 卸载软件
风格 命令
Debian apt-get remove package_name
Red Hat yum erase package_name
  • 更新软件包
风格 命令
Debian apt-get update; apt-get upgrade
Red Hat yum update
  • 通过软件包文件升级软件(非资源库)
风格 命令
Debian dpkg –install package_file
Red Hat rpm -U package_file
  • 列出所安装的软件包
风格 命令
Debian dpkg –list
Red Hat rpm -qa
  • 确定是否安装某个软件包
风格 命令
Debian dpkg –status package_name
Red Hat rpm -q package_name
  • 显示安装软件包的信息
风格 命令
Debian apt-cache show package_name
Red Hat yum info package_name
  • 查找安装某个文件的软件包
风格 命令
Debian dpkg –search file_name
Red Hat rpm -qf file_name

11.存储媒介

管理存储设备的第一步是把设备连接到文件系统树中。这个叫做 “挂载” 的过程允许设备连接到操作系统中

/etc/fstab 文件中可以查看系统启动时要挂载的设备,其中字段参见《Linux命令行大全》P184

1
2
3
$ mount # 不带参数会显示一系列当前挂载的文件系统(输出格式:设备 on 挂载点 type 文件系统类型(选项)),带参数则挂载文件系统
$ mount -t type /dev/sdb2 /mnt/test # 挂载文件系统 -t选项指定文件系统类型
$ umount /dev/sdb2 # 卸载硬件设备
  • 使用fdisk命令操作分区,参见《Linux命令行大全》P191
  • 使用mkfs命令创建一个新的文件系统,参见《Linux命令行大全》P193
  • fsck命令除检查文件系统完整性之外,还能修复受损的文件系统,其成功度依赖于损坏的数量

12.文件查找

locate 程序只能依据文件名来查找文件,而 find 程序能基于各种各样的属性搜索一个给定目录(以及它的子目录)来查找文件

locate和find命令较为详细说明请参见《Linux命令行大全》P220

  • locate:通过名字查找文件
  • find:在一个目录层次结构中搜索文件

13.归档和备份

gzip 程序被用来压缩一个或多个文件。当执行 gzip 命令时,则原始文件的压缩版会替代原始文件。相对应的gunzip 程序被用来把压缩文件复原为没有被压缩的版本

zip/unzip 压缩/解压缩文件包

同步文件和目录(rsync):rsync options source destination,更多请参见《Linux命令行大全》P244

14.正则表达式

1
$ grep [options] regex [file...]

grep选项列表参见《Linux命令行大全》P249

元字符(^ $ . [ ] { } - ? * + ( ) | \)和原义字符(除元字符外的其他所有字符)

锚点:插入符号^和美元符号$,意味着正则表达式只有在文本行的开头或末尾被找到时,才算发生一次匹配

正则表达式ˆ$(行首和行尾之间没有字符)会匹配空行

元字符 作用
.(圆点字符) 匹配任意一个字符
? 匹配零个或一个元素
* 匹配零个或多个元素
+ 匹配一个或多个元素
{} 匹配特定个数的元素
  • 中括号表达式和字符类

中括号表达式能从一个指定的字符集合中匹配单个字符。通过中括号表达式,我们能够指定一个待匹配字符集合(包含在不加中括号的情况下会被解释为元字符的字符)

一个字符集合可能包含任意多个字符,并且元字符被放置到中括号里面后会失去了它们的特殊含义。然而,在两种情况下,会在中括号表达式中使用元字符,并且有着不同的含义。第一个元字符是插入字符(ˆ),其被用来表示否定(必须是中括号表达式的第一个字符才具有否定的功能);第二个是连字符字符(-),其被用来表示一个字符范围

若要在正则表达式中包含一个连字符,则需要使连字符成为表达式中的第一个字符

  • 转换MS-DOS文本文件为Unix风格文本
1
$ tr -d '\r' < dos_file > unix_file

tr命令可以执行ROT13文本编码(简易加密类型) (两次执行恢复原来的文本)

15.格式化输出

  • nl:添加行号
  • fold:限制文件行宽
  • fmt:填充和连接文本行,同时保留空白符和缩进
  • pr:格式化打印文本(给文本分页)
  • printf:格式化打印,较为详细请参见《Linux命令行大全》P320
1
2
3
4
# 常用构建源码包命令
$ ./configure
$ make
$ make install

16.bash脚本

对于脚本文件,有两个常见的权限设置;权限为 755 的脚本,则每个人都能执行;权限为700 的脚本,只有文件所有者能够执行。注意为了能够执行脚本,脚本必须是可读的

  • 添加PATH变量的目录
1
2
$ export PATH=~/bin:"$PATH"
$ . .bashrc # 点(.)命令是 source 命令的同义词,一个 shell 内建命令,用来读取一个指定的 shell命令文件,并把它看作是从键盘中输入的一样

注意:shell在赋值过程中,变量名、等号和变量值之间必须没有空格

  • shell函数的两种语法形式

为使函数调用被识别出是 shell函数而不是被解释为外部程序的名字,在脚本中 shell 函数的定义必须出现在函数调用之前

在变量名之前加上单词 local,来定义局部变量

1
2
3
4
5
6
7
8
9
10
# name为函数名 commands为命令
function name {
commands
return
}
---
name () {
commands
return
}
  • if分支结构
1
2
3
4
5
6
7
if commands; then
commands
[elif commands; then
commands...]
[else
commands]
fi

当命令执行完毕后,命令(包括我们编写的脚本和 shell 函数)会给系统发送一个值,叫做退出状态。这个值是一个 0 到 255 之间的整数,说明命令执行成功或是失败。按照惯例,一个零值说明成功,其它所有值说明失败。Shell 提供了一个参数$?,我们可以用它检查退出状态

如果 if 之后跟随一系列命令,则将计算列表中的最后一个命令,到目前为止,经常与 if 一块使用的命令是 test。这个 test 命令执行各种各样的检查与比较。它有如下两种等价模式:

1
2
3
test expression
---
[ expression ] # 更为流行

这里的 expression 是一个表达式,其执行结果是 true 或者是 false。当表达式为真时,这个test 命令返回一个零退出状态,当表达式为假时,test 命令退出状态为 1;当与 test 一块使用的时候,> 和 < 表达式操作符必须用引号引起来(或者是用反斜杠转义)。如果不这样,它们会被 shell 解释为重定向操作符,造成潜在的破坏结果

计算文件状态的文件表达式,详细请参见《Linux命令行大全》P387

计算字符串表达式,详细请参见《Linux命令行大全》P390

计算整型表达式,详细请参见《Linux命令行大全》P391

  • 操作控制符
1
2
command1 && command2
command2 || command2

对于 && 操作符,先执行 command1,并且只有 command1执行成功后,才会执行 command2

对于 || 操作符,先执行 command1,并且只有command1 执行失败后,才会执行 command2

  • 读取键盘输入

read: 从标准输入读取单行数据。这个命令可以用来读取键盘输入,当使用重定向的时候,读取文件中的一行数据,详细选项参数请参加《Linux命令行大全》P403

1
read [-options] [variable...]
  • while/until循环

和 if 一样,while 计算一系列命令的退出状态。只要退出状态为零,它就执行循环内的命令;而 until 循环会继续执行直到它接受了一个退出状态零

跳出循环

break 命令立即终止一个循环,且程序继续执行循环之后的语句

continue 命令导致程序跳过循环中剩余的语句,且程序继续执行下一次循环

1
2
# while命令语法
while commands; do commands; done
  • case分支

早于 4.0的 bash,对于 case 语法绝不能匹配多个测试条件。现在的 bash 版本,添加“;;&”表达式来终止每个行动,其允许 case 语句继续执行下一条测试,而不是简单地终止运行

1
2
3
case word in
[pattern [| pattern]...) commands ;;]...
esac
  • for循环

传统shell格式的for循环中,variable 是一个变量的名字,这个变量在循环执行期间会增加,words 是一个可选的条目列表,其值会按顺序赋值给 variable,commands 是在每次循环迭代中要执行的命令

C语言格式的for循环中,expression1 用来初始化循环条件,expression2 用来决定循环结束的时间,还有在每次循环迭代的末尾会执行 expression3

1
2
3
4
5
6
7
8
9
# 传统shell格式
for variable [in words]; do
commands
done
---
# C语言格式(最新版本bash)
for (( expression1; expression2; expression3 )); do
commands
done

17.位置参数

  • 命令行访问

shell 提供了一个称为位置参数的变量集合,这个集合包含了命令行中所有独立的单词。这些变量按照从 0 到 9 给予命名,实际上通过参数展开方式你可以访问的参数个数多于 9 个。只要指定一个大于 9 的数字,用花括号把该数字括起来就可以。例如 ${10}、${55}、${211} 等等

确定命令行参数个数:$#

访问多个命令行参数:shift,执行一次 shift 命令,就会导致所有的位置参数“向下移动一个位置”。事实上,用 shift 命令也可以处理只有一个参数的情况(除了其值永远不会改变的变量 $0)

18.字符串和数字

  • 管理空变量的展开
1
2
3
4
5
6
7
${parameter:-word}(若 parameter 没有设置(例如,不存在)或者为空,展开结果是 word 的值。若 parameter不为空,则展开结果是 parameter 的值)

${parameter:=word}(若 parameter 没有设置(例如,不存在)或者为空,展开结果是 word 的值并且word的值会赋值给parameter。若 parameter不为空,则展开结果是 parameter 的值)

${parameter:?word}(若 parameter 没有设置(例如,不存在)或者为空,展开会导致脚本带有错误退出且word的内容会发送到标准错误。若 parameter不为空,则展开结果是 parameter 的值)

${parameter:+word}(若 parameter 没有设置(例如,不存在)或者为空,展开结果为空。若 parameter不为空,则展开结果会用word的值替换掉 parameter 的值但parameter的值本身不会改变)
  • 返回变量名的参数展开
1
2
3
${!prefix*}
${!prefix@}
# 这种展开会返回以 prefix 开头的已有变量名
  • 字符串展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
${#parameter} 展开成由 parameter 所包含的字符串的长度,通常,parameter 是一个字符串;然而,如果
parameter 是 @ 或者是 * 的话,则展开结果是位置参数的个数

${parameter:offset}
${parameter:offset:length}
上面两个展开用来从 parameter 所包含的字符串中提取一部分字符。提取的字符始于第 offset个字符(从字符串开头算起)直到字符串的末尾,除非指定提取的长度;若 offset 的值为负数,则认为 offset 值是从字符串的末尾开始算起,而不是从开头。注意负数前面必须有一个空格,为防止与 ${parameter:-word} 展开形式混淆。length,若出现,则必须不能小于零。如果 parameter 是 @,展开结果是 length 个位置参数,从第 offset 个位置参数开始

${parameter#pattern}
${parameter##pattern}
这些展开会从 paramter 所包含的字符串中清除开头一部分文本,这些字符要匹配定义的pattern。pattern 是通配符模式,就如那些用在路径名展开中的模式。这两种形式的差异之处是该 '#' 形式清除最短的匹配结果,而该 '##' 模式清除最长的匹配结果(贪心和非贪心匹配)

${parameter%pattern}
${parameter%%pattern}
这些展开和上面的 '#''##' 展开一样,除了它们清除的文本从 parameter 所包含字符串的末尾开始,而不是开头

${parameter/pattern/string}
${parameter//pattern/string}
${parameter/#pattern/string}
${parameter/%pattern/string}
这种形式的展开对 parameter 的内容执行查找和替换操作。如果找到了匹配通配符 pattern的文本,则string 的内容替换它。在正常形式下,只有第一个匹配项会被替换掉。在该 //形式下,所有的匹配项都会被替换掉。该 '/#' 要求匹配项出现在字符串的开头,而 /% 要求匹配项出现在字符串的末尾。/string 可能会省略掉,这样会导致删除匹配的文本

大小写参数转换,详细请参见《Linux命令行大全》P468

数基,详情参见《Linux命令行大全》P469

shell 算术只操作整型,所以除法运算的结果总是整数

常用赋值运算符及位运算符请参见《Linux命令行大全》P472~P473

  • bc 一种高精度计算器语言

19.数组

  • 创建数组
1
2
3
$ a[1]=abc # 访问时自动创建
$ declare -a abc # 创建数组abc(使用 -a 选项,declare 命令可以创建数组 abc)
# 数组第一个元素的下标是 0,而不是 1
  • 数组赋值
1
2
3
$ name[subscript]=value	# 单个数组元素赋值
$ name=(value1 value2 ...) # 多个值赋值
$ name=([num1]=value1 [num2]=value2 [num3]=value3 ...) # 指定下标把值赋给数组中的特定元素

输出整个数组的内容:下标 * 和 @ 可以被用来访问数组中的每一个元素。与位置参数一样,@ 表示法在两者之中更有用处

使用参数展开,我们能够确定数组元素的个数,与计算字符串长度的方式几乎相同;任何没有下标的对数组变量的引用都指向数组元素 0即第一个数组元素

其他数组操作请详见《Linux命令行大全》P486

  • 组命令和子shell (将命令组合在一起,用来管理重定向)
1
2
3
4
5
# 组命令
{ command1; command2; [command3; ...] }
# 子shell
(command1; command2; [command3; ...])
# 这两种形式的不同之处在于,组命令用花括号把它的命令包裹起来,而子 shell 用括号。值得注意的是,鉴于 bash 实现组命令的方式,花括号与命令之间必须有一个空格,并且最后一个命令必须用一个分号或者一个换行符终止

一个组命令在当前 shell 中执行它的所有命令,而一个子 shell(顾名思义)在当前 shell 的一个子副本中执行它的命令。这意味着运行环境被复制给了一个新的shell 实例。当这个子 shell 退出时,环境副本会消失,所以在子 shell 环境(包括变量赋值)中的任何更改也会消失。因此,在大多数情况下,除非脚本要求一个子 shell,组命令比子 shell更受欢迎。组命令运行很快并且占用的内存也少

  • 进程替换

管道线中的命令总是在子 shell 中执行,任何给变量赋值的命令都会遭遇这样的问题(子shell的任何变量赋值都不能传递给当前shell)。幸运地是,shell 提供了一种奇异的展开方式,叫做进程替换,它可以用来解决这种麻烦

1
2
3
4
5
# 适用于产生标准输出的进程
<(list)
# 适用于接收标准输入的进程
>(list)
# list为命令列表
  • 陷阱(当脚本接收到该程序即将提前终止的信号,此时让脚本执行如删除创建的临时文件等代码)
1
2
$ trap argument signal [signal...]
# 这里的 argument 是一个字符串,它被读取并被当作一个命令,signal 是一个信号的说明,它会触发执行所要解释的命令
  • 异步执行(wait命令导致一个父脚本暂停运行直到特定进程运行结束)

  • 命名管道

当在管道的另一端没有任何对象来接收数据时相关命令会挂起,这种现象被称为管道阻塞。一旦我们绑定一个进程到管道的另一端,该进程开始从管道中读取输入的时候,管道阻塞则会结束