6.Bash的功能
6.Bash的功能
本章介绍 Bash 的特色功能。
6.1 Bash的启动
  bash [长选项] [-ir] [-abefhkmnptuvxdBCDHP] [-o 选项] [-O shopt 选项] [参数 ...]
  bash [长选项] [-abefhkmnptuvxdBCDHP] [-o 选 项] [-O shopt 选 项] -c string [参 数 ...]
  bash [长选项] -s [-abefhkmnptuvxdBCDHP] [-o 选项] [-O shopt 选项] [参数 ...] 
除了单字符的命令行选项(参见[内部命令 set])外,还可以使用一些多字符选项。
要想正确解析命令行,多字符选项必须出现在单字符选项的前面。
    --debugger                 在shell启动前准备调试器分析。打开扩展的调试模式(参见[内部命令 shopt])和shell函数的跟踪(参见[内部命令 set])。
    --dump-po-strings      在标准输出中打印"$"后面的双引用字符串。除了输出的格式,其它和"-D"选项是等价的。
    --dump-strings            和"-D"选项等价。
    --help                          在标准输出中打印使用帮助后成功邟出。
    --init-file 文件名
    --rcfile 文件名              在交互式的 shell 中执行文件名 (而不是 ~/.bashrc) 中的命令。
    --login                        和"-l"选项等价。
    --noediting                 当 shell 交互式运行时,不使用GNU Readline库来读取命令行。
    --noprofile                  当 Bash 作为登录 shell 启动时,不加载系统或个人的初始化文件 /etc/profile、~/.bash_profile、 ~/.bash_login、~/.profile。
    --norc                         在交互式的 shell 中,不读取初始化文件 ~/.bashrc。如果用 sh 来启动 shell,这个选项默认就打开了。
    --posix                        如果 Bash 的默认行为与 POSIX 不同,就遵循 POSIX 规范。这个选项是用来让 Bash 成为该规范的一个超集。
    --restricted                 打开受限制模式。
    --verbose                   和“-v”选项等价,回显读取的输入行。
    --version                    在标准输出中显示当前 Bash 的版本信息后成功退出。 
启动时还可以指定一些单字符选项;这些选项是内部命令 set 所没有提供的。
    -c 字符串                    处理完选项以后从字符串中读取命令并执行,然后退出。剩余的参数赋值给从 $0 开始的位置参数。助记词: Command, 命令字符串
    -i                               强制 shell 交互式的运行。交互式的 shell 在[交互式的 shell]中介绍。助记词: Interactive, 交互的
    -l                               使当前 shell 表现得像登录后直接启动的那样。在交互式的 shell 中,这和用 exec -l bash 命令启动的登录 shell 是等价的。
                                     如果不是交互式的 shell,则执行登录 shell 的初始化文件。exec bash -l 或 exec bash --login 将把当前的 shell 替换成一个登录 shell。关于登录 shell 的特殊行为,请参见[Bash 的启动脚本]。
    -r                              把当前 shell 变为受限制的 shell (参见[受限制的 shell])。助记词: Login, 登录的
    -s                              如果给定了这个选项,或者处理选项以后没有剩余的参数,则从标准输入读取命令。这个选项可以用来在启动交互式的 shell 时指定位置参数。助记词: Startupfile, 初始化文件
    -D                             在标准输出中打印所有"$"后面的双引用字符串。如果当前的语言区域不是C或POSIX,则要对这些字符串进行翻译。这个选项隐含了“-n“选项,并且不执行命令。助记词: Debug, 语言翻译调试 
    [-+]O [shopt 选项]     shopt 选项是内部命令shopt所接受的选项。如果指定了shopt 选项,则”+O“就会设置这个选项,而”-O“重置它。
                                    如果没有指定shopt选项,则在标准输出中显示shopt所接受的选项名称和值。如果这时选项是“+O”,则以一种可以重新作为输入的格式来显示。助记词: Option, 选项
     --                            单个 -- 表示选项的结束并停止继续处理选项。它后面的任何参数都被当成文件名或参数。 
“登录 shell”是指其第零个参数的第一个字符是“-”,或者通过“--login”选项启动的shell。
“交互式”的shell是指启动时没有非选项的参数(除非指定了“-s”选项),没有指定"-c"选项,并且其输入和输出都与终端相连(通过 isatty(3) 查看),或者用"-i"选项启动的 shell。
更多细节请参[交互式的 shell]。
如果选项处理完毕还剩余参数,这时又没有指定"-c"或"-s"选项,则第一个参数就当作是包含shell命令的文件名。
如果通过这种方式启动Bash,则 $0 就设为该文件名,而位置参数就设为其余的参数。Bash会从这个文件中读取命令并执行,然后退出。
Bash的退出状态是脚本中最后一个被执行命令的退出状态。如果没有执行任何命令,则退出状态为 0。
6.2 Bash的启动脚本
本节介绍Bash如何执行其初始化文件。
如果这些文件存在但是不可读,Bash 就会报错。
文件名中的 波浪号会被扩展。
6.2.1 作为交互式的登录shell启动,或带有"--login"选项
当 Bash 作为交互式的 shell 启动时,或作为非交互式的 shell 但带有“--login”选项,它将先读取/etc/profile 里面的命令并执行 ,
然后依次搜索 ~/.bash_profile、 ~/.bash_login、 ~/.profile,然后读取并执行第一个存在并且可读的文件。
可以在 shell 启动时指定"--noprofile"选项来禁止这种行为。 
当一个登录 shell 退出时,Bash会读取并执行 ~/.bash_logout 里面的命令。
6.2.2 作为交互式的非登录shell启动
当启动一个交互式的非登录 shell 时,Bash 会读取并执行 ~/.bashrc 文件里面的命令。
这个行为可以用"--norc"选项来禁止。而"--rcfile 文件名"选项强制 Bash 从文件名中读取命令并执行,而不是从 ~/.bashrc 中。
所以,~/.bash_profile 文件通常在进行登录相关的初始化之前 (或之后) 包含下面这行:
if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
6.2.3 非交互式的启动
如果 Bash 非交互式的启动,例如为了运行一个脚本,它就会在环境中寻找 BASH_ENV 变量,如果找到就把这个变量扩展后的值当作一个文件名,并且从中读取命令并执行。
这就好像执行了下面的命令:
if [ -n "$BASH ENV" ]; then . "$BASH ENV"; fi
只不过这时并没有使用 PATH 来搜索这个文件。 
如上所说,如果非交互式的 shell 启动时指定了"--login"选项,Bash 就会试图从初始化文件中读取命令并执行。
6.2.4 作为sh启动
如果把 Bash 作为 sh 来启动,它就会尽量去模仿历史上的 sh 的启动行为,同时还保证遵循 POSIX 标准。
如果作为交互式的登录 shell 启动,或者作为非交互式的 shell 启动但却指定了"--login"选项,Bash会依次试图去读取 /etc/profile 和 ~/.profile 并执行其中的命令。
可以使用"--noprofile"选项来制止这种行为。
如果有交互式的 shell 中用名称 sh 来启动时,Bash 将会寻找 ENV 变量,如果找到就扩展它的值并把这个值当成文件名来读取和执行。
因为作为 sh 启动的 shell 不会读取和执行任何其它的初始化文件, 所以"--rcfile"选项不起作用。
如果用名称 sh 启动一个非交互的 shell,它就不会读取任何初始化文件。 
作为 sh 启动时,Bash 会在读取初始化文件以后进入 POSIX 模式。
6.2.5 启动POSIX模式
如果通过"--posix"选项以 POSIX 模式启动 Bash,它就会按照 POSIX 规范去使用初始化文件。
在这种模式下,交互式的 shell 会扩展 ENV 变量并在扩展结果所指示的文件在读取命令并执行。它不会读取其它初始化文件。
6.2.6 由远程的shell守护进程启动
Bash 会试图把它的标准输出和一个网络连接相关联,就好像它由远程的 shell 守护进程 (通常是 rshd或 sshd)启动的一样。
如果 Bash 以这种方式启动,它就会读取并执行 ~/.bashrc 里面的命令。而如果以 sh 来启动就不这么做。
可以使用"--norc"选项来制止这种行为,或者用"--rcfile"选项来强制读取另外一个文件,但 rshd 在启动 shell 时通常都不带这些选项,或者不允许指定它们。
6.2.7 启动时实际用户(组)号和有效用户(组)号不同
如果 Bash 启动时实际用户 (组)号和有效用户 (组天)不同,并且没有指定"-p"选项,它就不会读取初始化文件,也不从环境中继承 shell 函数;
如果环境中有 SHELLOPTS 变量,也会被忽略。这时,把有效用户号设为实际用户。
如果启动时指定了"-p"选项,则启动行为仍然这样,但不设置有效用户号。
6.3 交互式的Shell
6.3.1 什么是交互式的shell
交互式的 shell 是指它启动时没有非选项的参数 (除非指定了"-s"选项),也没有指定"-c"选项,并且标准输出和标准错误输出都和终端关联 (可以用 isatty(3) 查看),或者通过"-i"选项启动。
通常,交互式的shell 都读取和写入用户的终端。
"-s"选项可以在启动交互式 shell 时设置位置参数。
6.3.2 当前的shell是交互式的吗?
如果想在初始化脚本中检测 Bash 是否以交互方式运行,可以检测特殊变量 - 的值。如果它的值包 含"i",那么它就是交互的。
另外一种方法是,检查变量 PS1 的值;这个变量在交互式的 shell 中设置,而非交互的 shell 重置了它。 
代码清单4:Readline 启动脚本的例子 
# 第一种方法 
case "$-" in
 *i*) 
   echo 这个是交互式的 shell。 
   ;;
 *) 
   echo 这个不是交互式的 shell。 
   ;;
esac
# 第二种方法
if [ -z "$PS1" ]; then
  echo 这个不是交互式的 shell。
else
  echo 这个是交互式的 shell。
fi
6.3.3 交互式shell的行为
Shell在交互式运行时,会改变几个方面的行为:
    (1) 读取并执行初始化文件。 
    (2) 默认启用作业控制。已经启用作业控制时,Bash 就会忽略来自键盘的作业控制信号 SIGTTIN、SIGTTOU、SIGTSTP。 
    (3) Bash 会在读取第一行命令之前先扩展并显示 PS1,在读取多行命令的第二行和其余行之前扩展并显示PS2。 
    (4) Bash 会在打印主提示符 PS1 之前把变量 PROMPT_COMMAND 的值当成一个命令去执行。
    (5) 用 Readline从用户的终端读取命令。 
    (6) 在读取命令时,Bash 会检查 set -o 命令的 ignoreeof 选项的值,而不是接收到标准输入中的 EOF 后就立即退出。 
    (7) 默认启用命令历史和历史补全。在退出时,Bash 会把命令历史写入到 $HISTFILE 指定的文件中。 
    (8) 默认进行别名扩展。 
    (9) 如果没有定义任何陷阱,Bash 就忽略 SIGTERM 信号。
    (10) 如果没有定义任何陷阱,Bash 就捕获并处理 SIGINT 信号。SIGINT 信号可能会中断某些内部命令。
    (11) 如果打当了 huponexit 选项,交互式的登录 shell 在退出时会向所有的作业发送 SIGHUP 信号。
    (12) 忽略启动选项"-n"。"set -n"也不会起作用。
    (13) Bash 会根据变量 MAIL、MAILPATH、MAILCHECK 的值定期检查邮件。
    (14) 设置 set -u 后,扩展一个末定义的变量发生的错误不会导致 shell 退出。
    (15) Shell不会因为在扩展 ${var:?word} 时发生变量 var 未定义错误而退出。
    (16) Shell内部命令的重定向错误不会导致退出。
    (17) 如果在 POSIX 模式下运行,特殊命令返回错误状态不会导致 shell 退出。
    (18) 执行 exec 失败不会导致 shell 退出。
    (19) 解析器遇到语法错误不会导致 shell 退出。
    (20) 默认打当了内部命令 cd 对目录参数的简单拼写更正功能。
    (21) Shell会检查 TMOUNT 变量的值,如果打印提示符 $PS1 后,在其指定的秒数内没有读取到命令就会退出。
6.4 Bash条件表达式
条件表达式由复合命令 [[ 和内部命令 test 与 [ 使用。这些表达式可以是单目或者双目的。
单目表达式常常用来检测文件的状态。此外还有字符串运算符和数值比较运算符。
如果某个基本表达式的文件参数格式为 /dev/fd/N,则测试的是文件描述符 N。
如果某个基本表达式的文件参数是 /dev/stdin、/dev/stdout、/dev/stderr 之一,则测试的分别是文件描述符 0、1、2。 
下面除非特别说明,下列操作文件的表达式将跟随符号链接去操作其指向的目标,而不是操作符号链接本身。
    -a 文件              如果文件存在则为真。
    -b 文件             如果文件存在并且是个块设备文件则为真。
    -c 文件              如果文件存在并且是个字符设备文件则为真。
    -d 文件              如果文件存在并且是个目录则为真。
    -e 文件              如果文件存在则为真。
    -f 文件               如果文件存在并且是个常规文件则为真。
    -g 文件              如果文件存在并且设置了有效组号则为真。
    -h 文件              如果文件存在并且是个符号链接则为真。
    -k 文件              如果文件存在并且设置了"滞留位"则为真。
    -p 文件              如果文件存在并且是个命名管道 (FIFO) 则为真。
    -r 文件               如果文件存在并且可读则为真。
    -s 文件               如果文件存在并且其大小不为零则为真。
    -t 文件描述符     如果文件描述符已打开并且指向终端则为真。
    -u 文件              如果文件存在并且设置了有效用户号则为真。
    -w 文件             如果文件存在并且可写则为真。
    -x 文件              如果文件存在并且可执行则为真。
    -O 文件             如果文件存在并且被其有效用户号所拥有则为真。
    -G 文件             如果文件存在并且被其有效组号所拥有则为真。
    -L 文件              如果文件存在并且是个符号链接则为真。
    -S 文件              如果文件存在并且是个套接字文件则为真。
    -N 文件             如果文件存在并且上次读取过后被修改过则为真。 
    文件一 -nt 文件二            如果文件一比文件二新 (根据修改时间)或者文件一存在而文件二不存在则为真。 
    文件一 -ot 文件二            如果文件一比文件二旧 (根据修改时间)或者文件二存在而文件一不存在则为真。 
    文件一 -ef 文件二            如果文件一和文件二指向同样的设备或文件节点则为真。
    -o 选项名称                    如果 shell 的选项名称已设置则为真。可以用内部命令 set 的"-o"选项列出所有选项。
    -z 字符串                       如果字符串的长度是零则为真。
    字符串                           如果字符串的长度不是零则为真。
    -n 字符串                       如果字符串的长度不是零则为真。 
    字符串一 == 字符串二     如果字符串一与字符串二相等则为真。可以把 == 换成 = 以保证与 POSIX 一致。 
    字符串一 != 字符串二       如果字符串一与字符串二不相等则为真。 
    字符串一 < 字符串二        在当前语言区域中排序时,如果字符串一排在字符串二前面则为真。 
    字符串一 > 字符串二        在当前语言区域中排序时,如果字符串一排在字符串二后面则为真。 
    数值一 运算符 数值二       运算符是"-eq"、"-ne"、"-lt"、"-le"、"-gt"、"-ge"之一。在这些算术双目运算中,如果数值一分别为等于、不等于、小于、小于或等于、大于、大于或等于数值二则为真。数值一和数值二可以是正整数或负整数。
6.5 Shell的算术运算
Shell可以对算术表达式求值,它可以是 shell 扩展的结果,也可以由内部命令 let,或者 declare的"-i"选项来实现。 
求值时使用固定宽度的整数,并且不检查溢出,虽然它可以捕获到除以零的情况并报错。
运算符的优先级、结合性、以及值都和C语言相同。
下列运算符按优先级分组,并按优先级从高到低的顺序列出。
    i++ i--         后增和后减
    ++i --i         先增和先减
    - +              单目负号和正号 
    ! ~               逻辑取反,按位取反
    **                指数 
    * / %           乘,除,求余 
    + -              加,减
    << >>        按位左移,按位右移
    <= >= < > 比较
    == !=         相等,不等 
    &               按位与 
    ^               按位异或 
    |                 按位或
    &&            逻辑与
    ||                逻辑或
    cond ? expr1 : expr2                                    条件运算符
    = *= /= %= += -= <<= >>= &= ^= |=      赋值
    expr1,expr2                                                  逗号运算 
可以使用 shell 变量作为运算数。在进行求值之前会进行参数扩展。
在表达式中,还可以通过名称直接使用变量而无需参数扩展的语法形式。
如果是通过名称而不是参数扩展来使用变量,则对于未设置或设为空值的变量在求值时为 0。
在引用到一个变量时,或者对一个用 declare -i 设置了其 integer 属性的变量进行赋值时,就把这个变量当成算术表达式进行求值。
空值运算结果为 0。
要在表达式中使用一个 shell变量,不需要设置它的 interger 属性。 
以 0 开头的常量当作八进制数解释,而以"0x"或"0X"开头表示十六进制数。
此外,数值的格式是 [base#]n;其中的base是 2 到 64 之间的一个十进制数,它表示算术进制基数;而 n 是这个进制中的一个数。
如果省略了 base# 部分,则表示 10 进制。
大于 9 的数字依次用小写字母、大写字母、"@"、"_"来表示。
如果 base 小于或等于 36,则可以混合使用大小写字母来表示 10 到 35 之间的数。 
求值时按运算符的优先顺序进行。括号()可以用来改变运算顺序,括号中的子表达式先求值。
6.6 别名
对于简单命令中的第一个单词,别名可以把它替换成一个字符串。
Shell维护一个别名列表,可以用内部命令 alias 或 unalias 进行设置或删除。 
对于每条简单命令的第一个单词,如果没有引用,shell 都会去检查它是否有别名。如果有,这个单词就用别名中的文本替换。
"/"、"$"、"'"、"=" 以及前面列出的任一 shell 元字符都不能在别名的名称中出现;而要替换的文本中可以含有任何有效的 shell 输入,包括 shell 元字符。
检查别名时只测试替换文件中的第一个单词,但是与别名扩展后完全一样的单词不会再次被扩展。
例如,这就意味着可以把 ls 作为 ls -F 的别名,但是 Bash 不会递归的去扩展要替换的文本。
如果别名文本中的最后一个字符是空格或制表符, 则还要对命令中别名之后单词进行别名扩展。 
别名可以用 alias 命令来创建或列出,并用 unalias 命令删除。
在替换的文本中没有办法像 csh 那样使用参数。如果需要参数,则应该使用 shell 函数。
在非交互运行的 shell 中不会进行别名扩展,除非打开了 shell 的 expand_aliases 选项 。 
定义和使用别名的规则有点含糊。
Bash 在执行任何命令之前总是至少读取一整行。
别名是在读取命令时扩展的,而不是在执行时。
所以,同一行中另外一个命令定义的别名直到读取下一行输入时才能生效,而本行中该别名之后的命令不受它的影响。
执行函数时也有同样的问题。别名是在读取函数定义时扩展的,而不是在函数执行时,因为函数定义本身就是一条复合命令。
这样的结果就是,在函数内部定义的别名直到函数执行以后才能使用。
所以,为了安全,永远都在单独的行中定义别名,并且不要在复合命令中使用别名。 
不管出于什么目的,都应该优先使用 shell 函数而不是别名。
6.7 数组
Bash 中支持一维的下标数组变量和键值数组变量。
任何变量都可以作为下标数组来使用;内部命令declear 可以显式的声明一个数组。
数组的元素个数不受限制,赋值时不限制数组下标是否连续。
下标数组使用整数或算术表达式来访问元素,下标从零开始,而键值数组使用任意字符串来访问元素。 
如果用下面的语法形式给任意变量赋值就自动创建了一个下标数组: 
数组名[下标]=值 
其中下标被当成算术表达式,它的求值结果必须是一个大于或等于零的数。
显式声明一个数组的语法:
    declare -a 数组名 
    declare -a 数组名[下标] 
显式声明一个键值数组的语法:
    declare -A 数组名 
可以用内部命令 declare 或 readonly 来设置数组变量的属性。每个属性都会作用于数组中的每个元素。 
可以使用下面的复合赋值语句给数组赋值 
    数组名=([下标=]值 ... [下标=]值 )
如果给下标数组连续下标赋值时,不需要指定下标。
如果给下标数组赋值时指定了下标,就赋值给指定下标的元素;否则,要赋值元素的下标就是该语句所赋值的最后一个下标加上一。
下标是从零开始的。
给键值数组赋值时,必须指定下标。
这种语法形式对内部命令 declear 同样有用。
对单个元素赋值可以查上面介绍的形式: 数组名[下标]=值 
数组的任何元素都可以用: ${数组名[下标]}  的形式来引用。
这里必须使用大括号以免与 shell 的文件名扩展运算符向冲突。
如果下标是"@"或"*",则这个单词就扩展为数组中的所有元素。
只有在这个单词位于双引号之间时这两个下标才会有区别。
如果这个单词位于双引号中间,${变量名[*]} 就扩展为一个单独的单词,它是用 IFS 变量的第一个字符把数组名所有的元素连接在一起;而 ${数组名[*]} 把数组名中的每个元素都扩展成一个独立的单词。
如果数组中没有元素,则 ${数组名[*]} 的扩展结果为空。
如果双引用的扩展在单词中进行,则第一个参数扩展后就和原来单词的开头部分相连,而最后一个参数扩展后就和原来单词的结尾部分相连。
这和特殊变量"@"及"*"的扩展方法是类似的。
${#数组名[下标]} 会扩展成 ${数组名[下标]} 的长度。
如果下标是"@"或"*",则它就扩展为数组的长度。
使用数组时如果没有指定下标,就相当于指定了 0 作为下标。 
可以用内部命令 unset 来删除数组。
如果删除时指定下标,则只删除该下标处的元素。
如果删除时只指定了数组名,则删除整个数组。
删除时指定下标为"@"或"*"也会删除整个数组。 
内部命令 declare、local、readonly 都接受"-a"选项来指定下标数组,或"-A"选项来指定键值数组。 
可以用内部命令 read 的"-a"选项把从标准输入中读取的一组单词赋给数组,也可以用它从标准输入中读取值后赋给指定的数组元素。
内部命令 set 和 declare 可以重新设置输入格式,以便于显示数组的值。
6.8 目录栈
目录栈是一组最近访问过的目录。
内部命令 pushd 可以在更改当前目录时把目录压入到栈中;
内部命令 popd 可以把指定的目录从栈中移除并把当前目录设为被移除的那个目录;
而内部命令 dirs 可以显示目录栈的内容。
目录栈的内容还可以从 shell 变量 DIRSTACK 中获得。
6.8.1 用于目录栈的内部命令
A.dirs
语法:dirs [+N | -N] [-clpv] 
功能:列出当前目录栈中的目录。可以用 pushd 命令向目录栈添加目录,用 popd 命令从目录栈删除目录。
选项说明:
    +N       显示从零开始的第 N个目录 (在不带参数执行 dirs 所列出的内容中从左开始数)。
    -N        显示从零开始的第 N个目录 (在不带参数执行 dirs 所列出的内容中从右开始数)。
    -c         删除目录栈中所有目录。助记词: Clean, 清除
    -l          显示长列表;默认的列表会用波浪号来表示主目录。助记词: LongList, 长列表
    -p         列出目录时每个目录占一行。助记词: wraP, 分行
    -v         列出目录时每个目录占一行,每行前面都显示这个目录在栈中的位置。助记词: wraP, 分行
B.popd
语法:popd [+N | -N] [-n] 
功能:(如果没有参数)删除目录栈中的顶端目录,并用 cd 命令进入到新的栈顶目录中。
          dirs 命令列出的目录 第一个序号为 0。所以,popd 就相当于 popd +0。
选项说明:
    +N        删除从零开始的第 N个目录 (在不带参数执行 dirs 所列出的内容中从左开始数)。
    -N         删除从零开始的第 N个目录 (在不带参数执行 dirs 所列出的内容中从右开始数)。
    -n         在目录栈中删除目录时,禁止改变目录,即只操纵目录栈
C.pushd
语法:pushd [-n] [+N | -N | 目录] 
功能:在目录栈的顶端保存当前目录并进入目录中。如果没有参数,则交换栈顶的两个目录。
选项说明:
    -n         在目录栈中添加目录时不按常规改变当前工作目录,而只对目录栈进行操作。
    +N        轮转目录栈,从而把第 N个目录移到栈顶 (在 dirs 所列出的内容中从左开始数,第一个为零)。
    +N        轮转目录栈,从而把第 N个目录移到栈顶 (在 dirs 所列出的内容中从右开始数,第一个为零)。 
    目录      把当前工作目录加入到栈顶,然后进入目录
6.9 提示符的控制
Bash 在每次打印主提示符之前都会检查 PROMPT_COMMAND 变量的值。
如果设置了这个变量并且其值不为空,就执行这个值中的命令,就好像这些命令是从命令行输入的一样。
此外,下表列出了可以用于这个变量的特殊字符: 
\a              响铃字符。 
\d              当前日期,格式为"周 月 日",例如"Tue May 26"。 
\D{格式}     把格式传给 strftime3 并把其结果插入到提示符中;空的格式将会用当前语言区域的格式显示时间。大括号是必须的。 
\e              转义字符。 
\h             主机名中第一个"."之前的部分。 
\H            主机名。 
\j              当前 shell 管理的作业数目。
\l              Shell所在终端设备的文件基名。 
\n             换行符。 
\r              回车符。 
\s              Shell的名称,$0 的基名 (即完整文件名中最后一个斜杠后面的部分)。 
\t              24 小时制的当前时间,格式为"HH:MM:SS"。 
\T             12 小时制的当前时间,格式为"HH:MM:SS"。 
\@           12 小时制的当前时间,区分上午和下午。 
\A             24 小时制的当前时间,格式为"HH:MM"。 
\u             当前用户的用户名。 
\v             Bash 的版本号,例如 2.00。 
\V            Bash 的发行号,即版本号加上补丁级别,例如 2.00.0。
\w           当前工作目录,其中的 $HOME 部分省略成一个波浪号 (使用 $PROMPT_DIRTRIM 变量)。 
\W           $PWD 的基名,其中的 $HOME 部分省略成一个波浪号。 
\!             当前命令的历史编号。 
\#            当前命令的命令编号。 
\$            如果有效用户号为 0 就是 # 字符,否则就是 $ 字符。 
\nnn        ASCII 代码为八进制数 nnn 的字符。
\\             一个反斜杠。 
\[             开始一个不可打印字符的转义序列;可以在提示符中插入终端控制字符序列。 
\]             结束一个不可打印字符的转义序列。 
命令编号和历史编号通常是不一样的:一个命令的历史编号是它在历史中的位置,历史中可能包含了从历史文件中读取的命令;而命令编号是指在当前 shell 会话中已经执行的所有命令中的序号。 
这个字符串在解析以后还要根据 shell 的 promptvars 选项进行参数 扩展、命令替换、算术扩展、以及引用去除 ()。
代码清单5:控制提示符实例 
CL="\[\e[0m\]" 
GREEN="$CL\[\e[0;32m\]" 
BGREEN="$CL\[\e[0;32;1m\]" 
XORG="$CL\[\e[0;36m\]"
XRED="$CL\[\e[0;35m\]" 
BRED="$CL\[\e[0;35;1m\]" 
ORG="$CL\[\e[0;33m\]" 
DARK GRAY="$CL\[\e[1;30m\]" 
CYAN="$CL\[\e[1;36m\]"
BLUE="$CL\[\e[1;34m\]"
# 为了显示方便,下面一行用命令替换进行赋值。实际使用时应该用单引号。
PROMPT COMMAND=$(
  echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"
  NTTY=$(tty | cut -d"/" -f3-4)
  LS=$(ls | wc -l)
  LSA=$(ls -a | wc -l)
  L1a="$BLUE[$BGREEN\u$GREEN@\h:$NTTY\s$BLUE]$BLUE"
  L1b="$ORG\t$BLUE"
  L1c="$BLUE<$BRED\w$BLUE>$BLUE"
  L1d="($XRED$LS/$LSA$BLUE)$BLUE"
  L2="$CYAN\\\$$CL"
  export PS1="$L1a-$L1b-$L1c-$L1d-\n$L2 "
  #export PS1="[\u@\h:$NTTY\s]-\t-<\w:$LS/$LSA>-\n\\$ "
  history -a
)
# 实际使用时,上面一行也应该改成单引号
6.10 受限制的shell
如果通过 rbash 来启动 Bash,或者启动时指定了"--restricted"或"-r"选项,则 shell 就进入受限模式。
受限制的 shell 可以用来设置一个控制更严格的环境;它在行为上和 bash 完全一样,除了下面不允许的操作: 
    用内部命令 cd 改变目录。 
    设置或重置变量 SHELL、PATH、ENV、BASH_ENV 的值。 
    使用包含斜杠的命令名。 
    在内部命令 . 的参数中指定带有斜杠的文件名。 
    在内部命令 hash 的"-p"选项参数中指定带有斜杠的文件名。 
    启动时从 shell 环境中导入函数定义。 
    启动时解析 shell 环境中的 SHELLOPTS。 
    使用重定向运算符">"、">|"、"<>"、">&"、"&>"进行重定向。 
    使用内部命令 exec 把当前的 shell 换成另外一个命令。 
    使用内部命令 enable 的"-f"或"-d"选项增加或删除内部命令。 
    使用内部命令 enable 来启用已经禁用的 shell 内部命令。 
    指定内部命令 command 的"-p"选项。
    使用 set +r 或者 set +o restricted 来取消受限模式。 
这些限制是在读取启动文件以后生效的。
如果要执行的命令是个 shell 脚本,rbash 就会创建一个不带任何限制的 shell 来执行这个脚本。
6.11 Bash的POSIX模式
在 Bash 启动时指定"--posix"命令行选项,或者在 Bash 运行时执行 set -o posix 命令,都会使它改变那些与 POSIX 规范不一致的行为,从而更接近于 POSIX 规范。
如果作为 sh 来启动,Bash 就会在读取启动文件之后进入 POSIX 模式。
下面是这种模式中改变的行为: 
    (1) 如果散表列中的命令不存在了,Bash 会在 $PATH 中重新搜索基路径。这个行为也可以用 shopt -s checkhash 得到。 
    (2) 如果作业退出时返回状态不为零,作业控制代码及其内部命令打印的信息是"已完成 (状态号)"。 
    (3) 作业退出时,作业控制代码及其内部命令打印的信息是"已停止 (信号名)",其中信号名是诸如SIGTSTP 等名称。 
    (4) 内部命令 bg 使用指定的格式显示后台的每个作业,但不指明哪个是当前作业,哪个是前一个作业。 
    (5) 在能够识别保留字的上下文中出现的保留字不会进行别名扩展。 
    (6) 启用了 POSIX 方式来扩展 PS1 和 PS2,使得 ! 扩展成历史编号,而 !! 扩展成 !。并且,不管promptvars 选项如何设置,都会对 PS1 和 PS2 的值进行参数扩展。 
    (7) 执行 POSIX 的启动文件 ($ENV)而不是正常的 Bash 文件。 
    (8) 只对命令名之前的赋值进行波浪号扩展,而不是对本行中所有赋值都进行。 
    (9) 默认的历史文件是 \/.sh_history (这是 $HISTFILE 的默认值)。
    (10) kill -l 的输出是在单行中打印所有信号名,其间用空格分隔,并且不带 SIG 前缀。
    (11) 内部命令 kill 不接受带有 SIG 前缀的信号名。
    (12) 在执行". 文件名"时如果文件名不存在,则非交互的 shell 将会退出。
    (13) 非交互的 shell 在进行算术扩展时如果遇到无效的表达式而产生语法错误就会退出。
    (14) 重定向运算符不会对重定向中的单词进行文件名扩展,除非在交互式的 shell 中。
    (15) 重定向运算符不会对重定向中的单词进行单词拆分。
    (16) 函数名必须是有效的 shell 标志符;即它们不能包含字母、数字、下划线以外的字符,也不能以数字开头。在非交互的 shell 中如果定义的函数名无效则会导致一个严重错误。
    (17) 在搜索命令时,POSIX 的特殊命令会在函数名之前找到。
    (18) 如果 POSIX 的特殊命令返回错误的状态,则非交互的 shell 就会退出。严重错误是指 POSIX 规范中列出的那些,包括指定了不正确的选项,重定向错误,命令名之前的变量赋值错误,等等。
    (19) 如果设置了 CDPATH,内部命令 cd 就不会在其后隐式附加当前目录。这意味着如果在 $CDPATH 的任一条目中都找不到一个有效的目录,cd 就会失败,即使其参数指定的目录在当前目录中存在。
    (20) 如果变量赋值时发生错误并且其后没有跟着命令名,非交互的 shell 就会退出并返回错误状态。变量赋值会发生错误的例子包括试图给只读变量赋值。
    (21) 如果 for 语句中的循环变量或者 select 语句中的选择变量是只读变量,则非交互的 shell 就会退出并返回错误状态。
    (22) 不可以使用远程替换。
    (23) 在 POSIX 特殊内部命令之前的赋值语句,在命令执行完毕以后还将持续保留在 shell 环境中。
    (24) 在 shell 函数调用之前的赋值语句,在函数返回以后还将持续保留在 shell 环境中,好像未执行POSIX 特殊内部命令。
    (25) 内部命令 export 和 readonly 会按照 POSIX 要求的格式输出内容。
    (26) 内部命令 trap 显示的信号名称不带有 SIG 前缀。
    (27) 内部命令 trap 不会检查其第一个参数是否是一个信号指示,并且在是信号指示时恢复该信号的处理, 除非这个参数只含有数字并且指定了一个有效的信号。
          如果用户希望把某个信号的处理重置为原来的程序,则应该用"-"作为第一个参数。
    (28) 如果 PATH 中不包括当前路径,则内部命令 . 和 source 就不会在当前目录中搜索文件名参数。
    (29) 为执行命令替换而创建的子 shell 会继承父 shell 的"-e"选项。如果不是在 POSIX 模式中,Bash 会在这种子 shell 中重置"-e"选项。
    (30) 总是启用别名扩展,即使是在非交互的 shell 中。
    (31) 当用内部命令 alias 显示别名定义时,不会在每条输出前加上前导的"alias ",除非指定了"-p"选项。
    (32) 如果启动内部命令 set 时没有指定选项,它不会显示 shell 函数的名称和定义。
    (33) 如果启动内部命令 set 时没有指定选项,它在显示变量值时就不用引用,即使其中含有不可打印字符,除非这个值中含有 shell 元字符。
    (34) 如果使用了内部命令 cd 的逻辑路径模式,并且由 $PWD 和其参数指定的目录名构成的路径不存在,cd将会失败,而不是继续尝试物理路径模式。
    (35) 如果内部命令 pwd 指定了"-P"选项,它就会把 $PWD 转换成不带符号链接的路径后输出。
    (36) 内部命令 pwd 会检查其打印的路径是否和当前目录相同,即使没有用"-P"选项让它去检查文件系统。
    (37) 在列出历史条目时,内部命令 fc 不会指示每个条目是否已经被修改过。
    (38) fc 默认使用的编辑器是 ed。
    (39) 内部命令 type 和 command 不会报告不可执行的文件,尽管在 $PATH 中只有这个文件的名称匹配时 shell 会试图去执行它。
    (40) 在 vi 编辑模式中,"v"命令会直接启动 vi 编辑器,而不是去检查 $VISUAL 和 EDITOR。
    (41) 如果打开了 xpg_echo 选项,Bash 不会把 echo 命令的任何参数当成选项;而是对每个参数进行转义处理以后直接显示。
    (42) 内部命令 ulimit 的"-c"和"-f"选项使用 512 字节的块。 
还有一些 POSIX 行为,即使是 Bash 的 posix 模式在默认情况下也没有实现的。特别的: 
    (1) 当一个程序要编辑历史条目并且这时没有设置 FCEDIT 变量时,内部命令 fc 会再去检查 $EDITOR,而不是直接使用默认的 ed。只有在没有设置 EDITOR 时 fc 才会使用 ed。 
    (2) 如上所说,Bash 需要打开 xpg_echo 选项才能让内部命令 echo 完全遵循规范。 
在编译时,可以指定 --enable-strict-posix-default 把 Bash 配置成默认就支持 POSIX。
6.Bash的功能的更多相关文章
- 鸟哥的私房菜:Bash shell(一)-Bash shell功能简介
		
Bash shell系列里,由变量谈起,先讲到环境变量的功能与修改的问题, 然后会继续提到历史指令的运用.接下来,就会谈一下『数据流重导向』这个重要概念, 最后就是管线命令的利用! 一 Bash s ...
 - Linux学习笔记(15)shell基础之Bash基本功能
		
1 shell概述 shell是一个命令解释器,为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序.用户可以用shell启动.挂起.停止甚至是编写一些程序. shell是一个功能强大 ...
 - Linux系列教程(二十一)——Linux的bash基本功能
		
上篇博客我们介绍了什么是shell,以及编写shell脚本的两种执行方式.我们知道在敲命令的时候,有很多快捷键,比如tab键能补全命令,在比如为什么我们直接敲 ll 命令能显示目录的长格式,其实这是b ...
 - bash 基本功能
		
1 shell概述 shell是一个命令解释器,为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序.用户可以用shell启动.挂起.停止甚至是编写一些程序. shell是一个功能强大 ...
 - 『忘了再学』Shell基础 — 4、Bash基本功能(history命令)
		
目录 1.history历史命令 2.设置命令历史记录的条数 3.清空历史命令 4.历史命令的调用 5.命令与文件的补全 在Linux系统中默认的Shell就是Bourne-AgainShell(简称 ...
 - linux笔记:shell基础-bash基本功能
		
历史命令的调用: 命令和文件补全(如果当前有多个可选的补全,则按2次tab键,可以列出所有的可选项): 命令别名: 让别名永久生效: 删除别名: bash常用快捷键: 标准输入输出: 输出重定向: 输 ...
 - Linux学习 -- Shell基础  --  Bash基本功能
		
历史命令 history -c clear -w 写入 ~/.bash_history 默认保存1000条, 可在/etc/profile中修改 调用 Tab补全 命令.目录.文件 命令别名 ...
 - Shell基础 - Bash基础功能
		
历史命令 history选项: -c 清空历史命令 -w 立即保存历史命令Linux 下输入过的历史命令,都会保存在根目录下的:~/root/.bash_history 文件中默认保存 1000 条, ...
 - Bash基本功能
		
bash的基本功能 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 欢迎加入: 高级运维工程师之路 598432640 一.历史命令和命令补全 1.历 ...
 
随机推荐
- python小技巧之把list组合成chain
			
a=[] for i in range(10): a.append(i) for i,j in zip(a[:-1],a[1:]): print('%s=>%s'%(i,j)) 输出结果: 0= ...
 - 手把手教你在Linux系统下安装MongoDB
			
1. 下载最新的stable版MongoDB [root@spirit-of-fire ~]# wget http://downloads.mongodb.org/linux/mongodb-linu ...
 - js毫秒数转换为具体日期
			
[1].毫秒数转换为具体日期 function getMyDate(str) { var oDate = new Date(str), oYear = oDate.getFullYear( ...
 - 前端知识点回顾——Javascript篇(二)
			
JavaScript的解析顺序 第一阶段:编译期 寻找关键字声明的变量.函数声明的变量,同时会对变量进行作用域的绑定 var声明的变量,在编译期会赋一个默认值undefined,变量提升的特性. ES ...
 - Linux下 安装jdk8
			
一.文件准备 1.1 文件名称 jdk-8u121-linux-x64.tar.gz 1.2 下载地址 http://www.oracle.com/technetwork/java/javase/do ...
 - URL编码和解码
			
1. 为什么需要编码 当数据不利于处理.存储的时候,就需要对它们进行编码.如对字符进行编码是因为自然语言中的字符不利于计算机处理和存储.对图片信息.视频信息.声音信息进行压缩.优化,将其“格式化”,是 ...
 - CPU-内存-IO-网络调优
			
一.关于CPU 中央处理器调优 1. CPU处理方式: 批处理,顺序处理请求.(切换次数少,吞吐量大) 分时处理.(如同"独占",吞吐量小)(时间片,把请求分为一个一个的时间片,一 ...
 - DevOps - 微服务与Serverless
			
微服务 简介 "微服务"强调的是服务的大小,它关注的是某一个点. "微服务架构"则是一种架构思想,需要从整体上对软件系统进行通盘的考虑. 通俗来说,微服务架构就 ...
 - java-创建对象实例
			
1.A a = new A(); 2.Class class = B.Class; B b = class .newInstance();
 - vue中如何使用event对象
			
原文地址 一.event 对象 (一)事件的 event 对象 你说你是搞前端的,那么你肯定就知道事件,知道事件,你就肯定知道 event 对象吧?各种的库.框架多少都有针对 event 对象的处理. ...