Profil de liqing有个空间PhotosBlogListes Outils Aide

Blog


24 février

关于Bash翻译的整理

最近准备把已经翻译的内容从头开始整理一遍,主要是为了修正很多不通顺的中文语句,统一术语,并且把整个文档HTML化。 有兴趣的朋友可以看看我重新整理的内容。
19 février

我的翻译计划:Bash参考手册 第三章 基本功能 (8)

3.7.3 命令运行环境
shell的运行环境由下面的部分构成。
 
一个已打开文件的列表,这个列表是在shell被调用的时候从上一个运行环境继承而来的,当然可以在shell的执行环境中用内建命令exec来更改。
 
一个当前工作目录,继承于上个运行环境,可以用cd,pushd,popd更改。
 
创建文件用的掩码,继承于上个运行环境,用umask可以更改。
 
当前的信号处理用函数列表,用trap命令可以更改。
 
一些shell参数,继承于上个运行环境,可以用变量赋值的方式可以更改。
 
一些shell函数,继承于上个运行环境,可以用函数定义的方式可以更改。
 
一些shell的选项,在shell被调用时设定,用set命令可以更改。
 
一些用shopt设定的选项。
 
一些用aliase定义的重命名。
 
各种进程的ID,包括后台作业(见3.2.3 命令列表),其中包括$$和$PPID。
 
当调用内建命令和函数以外的单一命令的时候,就会启动一个新的运行环境。这个运行环境是由下面几个部分构成的。(除非有特殊的注解,否则下面的值都是从shell继承的。)
 
一个已打开文件的列表,其中有一部分内容是在命令启动时用重定向来指定的。
 
一个当前工作目录。
 
创建文件用的掩码
 
被标志为export的shell变量,其中包括专门为这个命令export的变量,专用的变量是用特殊的方法指定的(见3.7.4 环境变量/函数)
 
当前的信号处理用函数列表,特殊注解:在shell中设置的信号处理函数,都会被复原为从shell的父进程继承过来时的状态,而在shell中忽略的 信号处理 在当前进程也会被忽略掉。
 
在新的运行环境中运行的命令永远不会影响shell的运行环境。
 
命令替换和异步命令运行在一个从shell运行环境复制而来的子shell运行环境中,唯一的区别就是信号处理用函数会被复原到从shell的父进程继承过来时的状态。在管线操作中用到的内建命令也会被在子shell运行环境中执行。在子shell运行环境中进行的操作也不会影响shell的运行环境。
 
当命令是最后带有了 `&'并且作业控制没有激活的话。这个命令的标准输出就会被设定为空文件 `/dev/null'。否则的话,被调用的命令就会继承父进程的文件描述符列表,同时命令启动时的重定向也会对这个列表产生影响。
 
3.7.4 环境变量/函数
在命令被调用的时候,可以传递一些字符串,由它们来指定环境变量/函数。这些字符串是由 名字-值 的结构组成的,指定形式是 name=value.
 
bash提供了很多种操作环境变量/函数的方法。在调用命令的时候。shell扫描自己的环境变量/函数并在每次找到的时候就建立一个参数,把它标志为export,这样就能传递到子进程中去了。被执行的命令会继承这些环境变量/函数。用export或`declare -x' 可以增加或者删除需要传递到子进程的内容。当用命令改变这些变量与函数的时候,也会影响到shell当前的执行环境。一个进程启动时从shell那里继承的环境变量/函数被称作为初始化环境,shell可以在调用命令之前修改当前环境来为新的进程准备适当的初始化环境,可以用unset 或者`export -n'来删除某个环境变量/函数,也可以用export或者`declare -x' 来增加一个环境变量/函数。

在调用一个命令或者函数的时候可以传递一些专用的环境变量/函数,写法是在调用命令或者函数的语句的头部加上赋值语句(见3.4shell参数).用这种方式指定的环境变量/函数只会影响这一次调用。
 
如果shell选项 `-k' 被指定的话,那么所有在调用行中出现的赋值操作都会被被调用的命令继承(见4.3 内建命令set)(译注:举例来说就是设置了-k的话,`./command foo=bar` 中的foo=bar也会被传递到command中去。)
 
当bash调用一个外置的命令的话, 外置命令执行时的环境变量`$_'会设置为被调用程序的全路径,
 
 
3.7.5 退出码
对于shell来说,一个命令的退出码如果是0的话就是代表执行成功,而一个非0的值就代表启动失败或者执行过程中产生了错误。对于写惯了类c程序的的我们来说,似乎是有点颠倒了。这种颠倒的规则的设计理念是 命令的成功是唯一的,而失败是有多种情况的。举例来说,当命令是被信号N中止的时候,bash就用128+N来作为命令的退出码。
 
如果命令没有找到的话,用来执行这个命令用的进程(译注:因为是先fork再exec,所以就算没有命令也是有进程的)的退出码是127.如果命令是不可执行的文件的话,退出码是126。在展开或者重定向时候出现了错误的话,退出码是一个大于0的数。
 
退出码可以在Bash的条件判断命令(见3.2.5条件选择机制)或者 命令队列机制中(见3.2.3命令队列)使用.
 
同样,bash的内建命令也是遵守成功为0失败为非0的规则,所以它们的退出码也可以用在条件判断命令和命令队列机制中。所有的内建命令还有个统一的规则就是返回码是2的话表示错误的使用了该命令。

3.7.6 信号
当bash在交互模式的情况的时候,如果没有用trap指定任何信号处理函数的话,bash本身忽略SIGTERM(所以用`kill 0' 是不能中止一个交互模式的shell的,译注:`kill 0'就是指给自己和自己进程组的组员送SIGTERM信号),并且捕捉SIGINT(这样等待内建命令执行完的过程中,就可以中止它了)。当Bash收到了SIGINT的时候,他会中止任何执行中的内容。在任何情况下,bash都忽略SIGQUIT.如果作业控制是有效的话(见 7.作业控制),Bash还会忽略SIGTTIN, SIGTTOU, 和SIGTSTP.

当bash启动一个命令的时候会把这个命令的信号处理函数集设置为Bash本身启动时从bash的父进程继承来的状态。当作业控制是无效的情况下,异步命令忽略SIGINT和SIGQUIT的设置。而在命令替换方式中被执行的子命令会忽略键盘产生的作业控制信号SIGTTIN, SIGTTOU, 和SIGTSTP.

默认的,shell在收到了SIGHUP信号后退出。在退出之前,交互的shell会对所有的作业送出SIGHUP信号,无论它们是在执行中还是暂停状态。特别的,暂停状态下的作业还会收到一个SIGCONT来保证它们能够接受SIGHUP.如果不想让作业收到信号的话,可以用内建命令disown(见7.2 作业控制相关的内建命令)把某个作业从作业表中移除或者用disown -h把这个作业标示为不接受SIGHUP的作业。
 
当用shopt(见4.2 bash 内建命令)激活选项huponexit 的情况下,退出交互式的bash时候也会对所有的作业发送SIGHUP.
 
在bash等待命令结束的途中如果接收到了一个需要捕捉的信号的话,信号处理函数会一直等到命令中止了以后才会被调用。而当bash用内建命令wait来等待一个异步命令的过程中接收到需要捕捉信号的话,信号处理函数会立即被调用,然后wait就以一个大于128的退出码退出。
 
 3.8 脚本
脚本是包含了若干shell命令的文件。当启动bash的时候把脚本作为第一个非选项参数,且 `-c' 或者`-s' 都没有被指定的话(见 6.1 调用Bash),Bash会在执行脚本中的命令后退出。我们称这种运行模式的Bash为非交互式shell.这种运行模式下 脚本的搜索顺序是 优先当前目录然后才是$PATH。
 
特别的,在bash运行一个脚本的时候,参数0会被设置为脚本的文件名而不是bash自己的,而其余的Positional Parameters还是遵照老规矩,设置为后继指定的参数。如果没有指定任何参数的话,那么Positional Parameters会被unset。

如果用chmod 把脚本置为可执行的话,那也可以直接启动它。不过这个时候的搜索路径只包括%PATH而不包括当前路径,启动的时候会分裂出一个子shell来执行脚本。

换句话说 执行 
 filename arguments
等效于执行
 bash filename arguments
 
在直接启动脚本的情况下。分裂出来子shell会重新初始化自己,就好像在一个用一个全新的shell来执行脚本,但是有一个特例,子shell会继承父shell中的命令缓存(见4.1bourne shell内建命令中关于hash的描述),所以脚本执行时的命令的搜索方式会受到一定的影响.(译注:还没有验证)
 
大多数版本的unix 都遵守下述的规则。如果脚本的第一行2以`#!'开头的话,这一行接下来部分会被认为是 执行脚本用的解析器,可以指定为bash,awk, Perl 或者其他的什么。当然,除了这一行以外的内容需要能被指定的解析器认知才好。
接着上面说的的那一行,在执行脚本用的解析器后面 还可以依次指定如下可选内容, 首先是一个 解析器选项,然后是脚本的名字(译注:解析器为bash的情况下,在这里指定了其他的脚本的话,这次运行就和这一行所在的脚本本身没有关系了),接来下是 一些传递给脚本的参数。Bash会替操作系统调用`#!'后的的内容。要注意的是,有些版本的unix限制了`#!'后的内容最多能使用32个字符。
 
对于Bash专用的脚本,一般在开头的地方需要指定#! /bin/bash  (假设bash安装在`/bin'),因为这样做可以保证 即使在其他shell下被调用,也能让bash来执行该脚本。

 
 
 
8 février

我的翻译计划:Bash参考手册 第三章 基本功能 (7)

3.7 执行命令
 
3.7.1 扩展单一的命令 介绍bash在执行单一的命令前如何扩展他们。
3.7.2 命令的定位与执行  bash怎么找到命令并且执行他们。
3.7.3 命令执行环境 当执行非内建命令的时候,执行环境是如何的。
3.7.4 环境变量 命令执行的环境变量是什么。
3.7.5 退出码 bash如何解释命令执行的结果代码
3.7.6 信号 当bash或者某个命令接收到某个信号的时候会发什么
 
3.7.1 扩展单一的命令。
当一个单一的命令被执行的时候,shell会从左到右执行如下的扩展、赋值和重定向操作
1.那些被解析器认为是赋值(出现在命令名称之前)或重定向操作的单词会被保存起来,以备后用。
 
2.而那些不是赋值或者重定向的单词都会被扩展。(见3.5节 shell扩展)。扩展后产生的结果中第一个单词被认为是命令名,接下来的就是参数。
 
3.关于重定向的执行已在前面的章节介绍过了(3.6重定向)
 
4.在变量赋值语句中,`=' 后的字符串需要经过波浪号expansion,参数expansion,命令替换,算数expansion和引用除义之后才能被赋给相应的变量。

如果经过扩展后的结果中没有命令名的话,那么变量赋值的操作就会影响到当前的shell环境。否则,被赋值的变量就会加到需要执行的命令的环境变量中而不影响当前的shell环境。任何给只读变量赋值的操作都会引发一个错误, 而且整个命令的返回值是非0。
 
如果经过扩展后的结果中没有命令名的话,重定向操作虽然也会被执行,不过不会影响当前的shell环境。如果有重定向错误发生的话,命令就会以非0码退出。
 
如果经过扩展后的结果中有命令名的话,命令就会按照后面叙述的流程继续执行。否则的话,命令就退出了。如果扩展过程中包括命令替换过程的话,整个命令的退出值就是最后一个命令替换过程中被执行的命令的退出值。如果不包括命令替换的话,命令的退出值是0
 
3.7.2 搜索并且执行命令
当命令经过展开后的结果是一个单一命令以及它的参数(可选)情况话,就会执行下面的一系列处理。
 
1,如果命令名中不带斜杠的话,shell就尝试着对这个命令进行定位。如果命令名正好可一个shell函数符合的话,那么这个函数就会被调用。具体见3.3shell函数
 
2.当不能在函数中发现这个命令的情况下,shell就对自己内建命令的列表进行搜索。如果可以找到匹配项的话,匹配项就会被执行。
 
3.当上述的2次搜索都不能找到匹配项,且命令名不含斜杠的话,Bash就搜索$PATH内的每个目录来确定命令文件位置。bash内建了一个hash表来记住被检索到的可执行文件的全路径以避免多次重复搜索,所以只有在bash内建的hash内找不到这个命令的时候才会进行搜索。如果这次搜索还是找不到匹配项的话,bash就打印出错误信息并且以127退出。
 
4.如果搜索成功或者命令名里面带有斜杠的话,shell就会在另外一个运行环境中执行这个命令.参数0就是用户指定的命令名(带斜杠,如果有的话),接下来的参数就是用户在命令行中指定的命令执行参数。
 
5.当搜索到的文件不是可执行文件而且不是一个目录的话,这个文件就会被作为一个脚本文件被执行(见 3.8 Shell 脚本)
 
6.当命令不是异步启动的话的,shell就会一直等到命令结束,并且取得他的返回值。
 
1 février

我的翻译计划:Bash参考手册 第三章 基本功能 (6)


3.6 重定向
在任何命令执行之前,它的输入输出可以用特殊的语法来重定向。同样重定向也可用来改变当前的执行环境,比如打开或者关闭某些文件。接下来要说明的一些重定向操作符可能出现在命令的前面后面或者中间。重定向的处理顺序是由它们出现的顺序来决定的,从左到右。
在下面的叙述中,如果文件标示被省略,且重定向操作符的第一个字符是`<'的话,那么这次重定向针对的就是标准输入(file descriptor 0).如果重定向操作符的第一个字符是`>'的话,重定向针对的就是标准输出(file descriptor 1).
除非有特殊的说明,接下来要说明的内容中,重定向操作符之后的单词,都会经过花括号expansion, 波浪号expansion,参数expansion, 命令替换, 算术expansion, quote removal, 文件名expansion, 和 单词分割.如果经过这一系列expansion后产生了多一个单词的话,bash就会报错。
要注意的是重定向出现的位置和顺序是非常重要的。比如,命令 ls > dirlist 2>&1
把标准输出(file descriptor 1)和标准出错(file descriptor 2)定向到dirlist。而命令 ls 2>&1 > dirlist
只把标准输出定向到dirlist,而且在这之前,标准出错被复制成了标准输出。

当使用重定向功能的时候,bash提供了几个特殊的文件名。
/dev/fd/fd
如果最后的fd是一个合法的整数n的话,那么就代表file descriptor n
/dev/stdin
代表file descriptor 0
/dev/stdout
代表file descriptor 1
/dev/stderr
代表file descriptor 2
/dev/tcp/host/port
如果host是合法的hostname或者网络地址,且port是一个整数或者是一个serivce的名字,那么就代表对这个地址:端口的tcp访问。
/dev/udp/host/port
如果host是合法的hostname或者网络地址,且port是一个整数或者是一个serivce的名字,那么就代表对这个地址:端口的udp访问。
当打开或者创建文件出错的时候,会导致重定向失败。
 
 
3.6.1 重定向输入
对于输入的重定向会以读方式打开文件(expansion后的结果)于file descriptor n(也就是说可以用过n来读取这个文件)。当n没有指定的话,
就在标准输入上打开。
重定向输入的标准写法是:[n]<word

3.6.2 重定向输出
对于输出的重定向会以写方式打开文件(expansion后的结果)于file descriptor n(也就是说可以用过n来写入这个文件)。当n没有指定的话,
就在标准输出上打开。如果文件不存在的话就会被创建出来,反之文件会被清空。
重定向输出的标准写法是:[n]>[|]word
 
如果使用`>'的形式对一个已经存在的普通文件进行操作的话,当内建选项noclobber 开启的时候,操作会失败。如果使用`>|'这样的形式或者
noclobber 没有开启的话,则可以正常的对既存的普通文件进行操作。
 
 
3.6.3 追加形重定向输出
这种形式的输出重定向会以追加写方式打开文件(expansion后的结果)于file descriptor n(也就是说可以用过n来追加内容在这个文件后面),
当n没有指定的话,就在标准输出上打开。如果文件不存在的话就会被创建出来。
追加形重定向输出的标准写法是:[n]>>word
 
 
3.6.4重定向标准输出与标准错误
bash 允许把标准输出(file descriptor 1)与标准错误(file descriptor 2)重定向到其他文件中。
有2种格式:&>word 和>&word
一般我们使用前一种方式,它基本等效于>word 2>&1
 
3.6.5 Here Documents
如果使用here documents方式的重定向的话,shell就会从当前的源文件中读取需要的输入,当事前定义的特殊单词(word)单独出现在一行中的
时候就表示输入结束了(注意,作为结束符的这个单词不能有前后空格。)。所有读入的内容都作为命令的标准输入。
Here Documents 的语法是这样的:   <<[-]word
        here-document
delimiter
在word上不会发生参数expansion, 命令替换,算数expansion或者文件名expansion。如果在word中任何一个字符带有引用符号(译著:`"' `''
或者`\')的话,shell会把word进行引用除义后的结果去匹配delimiter,而且here-document中任何输入行都不会被进行任何的expanded.反之
,所有的输入行都会经过参数expansion, 命令替换,算数expansion后才作为标准输入被读入。在后一种情况下,\newline就会被忽略,而且
`\'必须被用来引用字符`\', `$', and ``'.
如果使用`<<-'形式的话,所有的头部的tab都会被忽略,包括delimiter这一行,这样就方便了用户在脚本中使用。
 
 
3.6.6 Here Strings
一种here documents 的变体,语法是: <<<word
 
经过expanded 后的word就会被用作命令的标准输入。

3.6.7 复制文件描述符
 [n]<&word 这种形式的重定向操作符是用来复制输入型的文件描述符。如果word经过扩展后的结果是1位或者1位以上的数字X的话,那么文件
描述符n就会成为文件描述符X的一份拷贝。如果在X指定的文件描述符上没有打开一个用于输入的文件的话,就会发生重定向错误。如果word经
过扩展后成为了`-'的话,文件描述符n就会被关闭。当n被省略的时候,默认是对标准输入(文件描述符0)进行处理。
类似的,[n]>&word这种形式的重定向操作符是用来复制输出型的文件描述符的。当n被省略的时候,默认是对标准输出(文件描述符1)进行处理
。当word经过扩展后的结果后产生的数字代表的文件描述符上没有打开任何输入型的文件的话,就会发生重定向错误。作为特殊的情况,如果n
省略,而且word经过扩展后的结果不是数字的话,那么标准出错和标准输出(译著:这里应该是只定向标准输出)就会按照以前描述的方式进行重
定向(译著:就是说abc=c:\\def.txt;ls >$abc执行后会把ls 的标准输入定向到c:\def.txt).
 
 
3.6.8 移动文件描述符
 [n]<&digit- 形式的重定向操作符是用来移动文件描述符的。
把文件描述符digit移动到文件描述符n(当省略的时候为0), 基本的行为就相当于把文件描述符digit拷贝到n,然后关闭digit.
类似的[n]>&digit- 形式的重定向操作符也是用来移动文件描述符的。不同的就是当n省略的时候使用的1。

3.6.9 以读写的形式打开文件
 [n]<>word 这个操作形式使扩展word后产生的文件名以用读写的方式在文件描述符n(默认为0)上被打开。如果文件不存在的话就会被创建出来
 
22 janvier

我的翻译计划:Bash参考手册 第三章 基本功能 (5)


3.5.8 文件名扩展
当经历了单词分割以后,除非指定了 `-f'选项(见4.3 内建命令 set),否则Bash 从每个单词中查找`*', `?', 和 `['. 如果一个单词中拥有其中任何一个字符的话,它就被认为是一个模式,而且整个单词会被匹配这个模式的文件名列表(以字母顺序排列)所替换。如果没有文件能够匹配这个模式,而且shell的选项nullglob被设置为无效的话,那么整个单词就会不经过文件名列表替换而被保留下来。如果nullglob设置为有效且找不到文件的情况下,整个单词就会被删除。当nocaseglob这个shell选项设置为有效的话,文件列表匹配是不区分大小写的。
 
 3.5.8.1 Pattern 匹配 shell如何来匹配模式
 除了下面列表的字符以外,每个在pattern中出现的字符都匹配它本身。
NUL可能不会出现在一个pattern中。特殊的pattern必须被引用起来才能用他本身字面的意思来匹配。
 特殊pattern 字符有下列的含义。
* 匹配任何的字符串,包括null
? 匹配任意一个字符。
[...] 匹配括号中的任意一个字符。如果2个字符之间用连字符-来分割的话,那么这就是一个范围表达式。
 在本地环境设置下,任何在这2个字符范围中的字符,包括这2个字符本身都会被匹配.如果在左括号[后的第一个字符是`!'或者 `^'的
话,那么在这个范围以外的字符都会被匹配。如果要单纯的匹配一个`-'的话,可以把它放在整个表达式的最前面或者最后。同样如果要单纯的
匹配一个`]'的话,那就把它放在整个表达式的最前面。关于本地环境设置,主要是是由当前的locale 设置和shell变量 LC_COLLATE 的值决定
的。
 举例来说,在默认的C 的本地环境下。`[a-dx-z]'等同于`[abcdxyz]',很多本地环境根据字典进行排序,在这样的环境下,`[a-dx-
z]'就可能等同于`[aBbCcDdxXyYz]'.为了精确的使用范围表达式,你可以强制的设置环境变量LC_COLLATE 或者 LC_ALL 的值为`C'.
 在`[' 和 `]'中,可以用[:class:]来设置字符种类,POSIX 1003.2定义的标准种类如下。
alnum   alpha   ascii   blank   cntrl   digit   graph   lower
print   punct   space   upper   word    xdigit
 一个字符种类可以匹配任何的属于这个种类的字符。比如word这个字符种类就能匹配字母,数字和`_'.
 在`[' 和 `]'中,一个equivalence class(等同类)? 可以用[=c=]来指定,equivalence class可以用来匹配在本地环境下与字符c具
有相同权重的字符。(译注:没有试过,主要意思可能是如果用半角的字符的话,就能匹配中文环境下的一个全角字符,不知道1和壹能不能匹
配起来。)
 Within `[' and `]', the syntax [.symbol.] matches the collating symbol symbol. (译注:待调查,没看懂)
 
 如果用内建命令shopt 打开了shell选项extglob 的话,很多扩展的模式匹配运算符就能使用了。下面的说明中,所谓的pattern-list
就是一个用`|'分割的列表。组合的模式可能是由一个或者多个下面要说明的子模式组成的。
 ?(pattern-list)
 匹配0次或者1次pattern-list

 *(pattern-list)
 匹配0次或者多次pattern-list
 +(pattern-list)
 匹配1次或者多次pattern-list
 @(pattern-list)
 匹配1次pattern-list 
 !(pattern-list)
 匹配任何pattern-list不能匹配的内容
 
3.5.9 Quote Removal
 经过了前述的expansions, 任何没有被引用的而且不是由前面的expansions 生成的`\', `'',和 `"' 都会被删除。
 

 
4 juin

我的翻译计划:Bash参考手册 第三章 基本功能 (4)


3.5 Shell Expansions
在命令行被分成一个个tokens之后Expansions 机制就会开始运作。一共有7种可以被运作的expansion。
●花括号expansion
●波浪号expansion
●参数和变量expansion
●命令替换
●算术expansion
●单词分割
●文件名expansion
3.5.1 花括号expansion 扩展一个在花括号内的表达式
3.5.2 波浪号expansion 扩展字符~
3.5.3 参数和变量expansion 描述了bash是怎么样扩展一个变量倒他的值。
3.5.4 命令替换 如何把命令的输出作为一个参数来使用
3.5.5 算术expansion 在shell中如何进行算术运算。
3.5.6 进程替换 一种和命令进行io的方法。
3.5.7 单词分割 expansion的结果是如何分割成不同参数的。
3.5.8 文件名expansion 用pattern来方便的引用文件名的方法。
3.5.9 除去引用符号 除去应用符号的时机与方法。
expansion的顺序是:花括号expansion,波浪号expansion ,参数expansion,变量expansion ,算术expansion,命令替换(由左向右),单词分割,文件名expansion。
在系统支持的情况下,还有一个特殊的expansion可以使用:进程替换。这个过程是和参数,变量,算术expansion及命令替换同时进行的。
花括号expansion和单词分割,文件名expansion会在执行操作后改变单词的数量;其他的expasion 只会把一个单词扩展成另外一个单词。但是有2个特例,一是 "$@" (见3.4.2特殊参数),二是"${name[@]}" (见6.7数组)
当所有的扩展结束以后就会除去引用符号(见3.5.9 除去引用符号)。
3.5.1 花括号expansion
花括号expansion是用来生成各种字符串的。这个机制类似于文件名expansion(见3.5.8文件名expansion),但是生成的文件名字符串不需要有对应的文件存在。花括号expansion的格式是由0个或者多个字符打头,然后是在花括号内一系列用逗号分割的字符串,后面是0个或者多个字符结尾。经过处理后,打头的字符串附加到花括号中每个字符串的前面。结尾的字符串附加到花括号中每个字符串的后面,整个处理过程是从左往右的。
花括号expansion是可以内嵌的。整个处理的结果是不排序的,保持原来从左到右的顺序。比如
bash$ echo a{d,c,b}e
ade ace abe
花括号expansion是最早执行的expansion,所以对于其他的expansion具有特殊意义的字符都必须被原封不动的保留在处理的结果里。它是严格保留原文的。Bash对于花括号中的内容不做任何语法上的解释。为了避免和参数expansion的冲突,形式为`${'的字符串不会进行花括号扩展。
正确的花括号expansion的格式必须包括没有被引用的左右花括号,和至少一个没有被引用的逗号。任何其他的格式都不会触发花括号expansion。
以下是2个花括号扩展的例子
mkdir /usr/local/src/bash/{old,new,dist,bugs}
或者
chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}

3.5.2 波浪号expansion
如果一个单词由一个未被引用的波浪号(`~')开头的话,那么这个单词中从波浪号开始直到第一个未被引用的(`/')(如果有的话)的前一个字符为止的所有字符都被称为"tilde-prefix".如果tilde-prefix内没有被引用的字符的话,那么除了波浪号以外的字符会被尽量的理解为用户名.当tilde-prefix只包含一个(`~')的话,那么它就会被替换为shell变量HOME。如果HOME是unset的话,那么就会被替换为执行这个shell的用户的home目录(译注:应该是passwd里面设定的那个目录把)。当tilde-prefix除了波浪号以外还包含用户名的话,那么整个tilde-prefix就会被替换成那个用户的home目录了。
如果tilde-prefix 写成`~+'的话,那就会被替换为shell变量PWD ,如果 写成`~-'的话,就会被替换成shell变量OLDPWD.
还有一种形式的tilde-prefix 内包含了一个数值N,并且可能在N前带有一个`+'或者 `-'号。这样的tilde-prefix会被替换为当前的目录堆栈(译注:就是用pushd造出来的那个)。具体的替换方法就好像用的tilde-prefix内的(+|-)N作为参数来调用dirs命令所得到的结果。如果没有设置`+'或者 `-'号的话,默认是用`+'.
如果,用户名不存在或者整个expansion失败的话,那么整个单词就原封不动的留下去了。
在进行变量赋值的时候,波浪号expansion也会被执行,通常可以用它来设置PATH, MAILPATH, and CDPATH的值。
下面概括了Bash如何处理tilde-prefixes的
~
The value of $HOME
~/foo
`$HOME/foo'
~fred/foo
The subdirectory foo of the home directory of the user fred
~+/foo
`$PWD/foo'
~-/foo
`${OLDPWD-'~-'}/foo'
~N
The string that would be displayed by `dirs +N'
~+N
The string that would be displayed by `dirs +N'
~-N
The string that would be displayed by `dirs -N'
  
3.5.3 shell 参数 expansion
 
 
以`$'开头的字符串可能是参数expansion,命令替换expansion或者是算数expansion。可以用花括号把需要替换的参数名字或者符号括起来,这样就可以避免在某些情况下变量名被部分替换。(译注,比如有变量ABC和ABCDE,用$ABCDE 的话就会被解析成ABC的值加上字符串DE,而使用${ABCDE}就能正确的取出ABCDE的值了)
当使用了花括号的情况下,第一个没有被反斜杠和引号引用的,并且不存在于任何内嵌的算术expansion,命令替换expansion,参数expansion内的`}'被认为是可以匹配的结尾花括号。
基本的参数expansion 形式是${parameter},整个表达式被替换为parameter的值。当parameter是一个2位或者2位以上的数字表示的positional parameter或者是为了保证parameter名的精确性,加上花括号是必需的。
如果parameter的第一个字符是感叹号的话,会触发间接的参数expansion,Bash把感叹号后的参数名对应的值作为参数名进行本次扩展。这被称作indirect expansion 。这种形式的写法有一个特例${!prefix*},后文中会有记述。
在下面要举的例子中,word会经过波浪号expansion,参数expansion,命令替换,和算术expansion 的处理。
除了截取类的expansion,Bash都会对参数进行测试,来决定它是unset或者是null,如果省略了下例中的冒号的话(:),那么Bash就只进行unset的测试,反过来说,如果指定了冒号的话,expansion操作会确定参数是存在的,并且值不是null.如果冒号省略的话,则只会测试参数是不是存在。
${parameter:-word}
 一般情况下parameter的值成为扩展的结果。
 如果parameter是unset或者null,扩展的结果就是经过expansion处理后的word。
${parameter:=word}
 一般情况下parameter的值成为扩展结果。 
 如果parameter是unset或者null,parameter就会被赋值为经过expansion处理后的word。然后这个值就成了扩展的结果,Positional参数和一些特殊参数不能应用这种形式。
${parameter:?word}
 一般情况下parameter的值成为扩展结果。
 如果parameter是unset或者null,经过expansion处理后的word会被显示在stderr上(如果word没有指定的话,会显示一个默认的消息),然后程序会以1为返回值退出(在非交互式shell的情况下)。
${parameter:+word}
 一般情况下,经过expansion处理后的word的值成为扩展结果。
 如果parameter是unset或者null,扩展的结果为空。
${parameter:offset}
${parameter:offset:length}
 扩展的结果是offset开始的length个字符串,如果不指定length就是从offset开始的所有字符串。length和offset是算数表达式(见6.5shell算术)。这种扩展方法称为Substring Expansion.
 length必须是大于或者等于0的值。如果offset是一个负数的话,则是指从字符串尾部开的的位置。如果parameter是`@',那么扩展的结果是从offset开始的length个 positional parameters.如果parameter是索引设置为`@'或`*'的数组的话,扩展的结果是从offset开始的length个数组元素。offset是0开始的,除非是在解析 positional parameters的情况下,这时候是1开始的。
 

${!prefix*}
 扩展的结果是以参数名以prefix开头的所有参数名,之间用IFS的第一个字符分割
${#parameter}
 扩展的结果是parameter的值的长度。如果parameter是 `*' 或者 `@',扩展的结果是 positional parameters的个数,同样使用数组的时候,返回的也是数组元素的个数。

${parameter#word}
${parameter##word}
 经过扩展处理后的word被看作是一个pattern (这种pattern的详细描述可以见3.5.8文件名expansion),如果pattern能够从头开始匹配parameter的值得话,那么扩展的结果就是parameter的值删除了可以被pattern匹配的前缀后的结果。#和##的区别就是指定pattern是按照最短匹配还是最长匹配。如果parameter指定的是`@' or `*',那么就会挨个处理每个positional parameter,然后把处理后的结果组成一个列表作为整个扩展的结果。同样的处理也应用在parameter被指定为数组的时候.

${parameter%word}
${parameter%%word}
 整个处理和上个例子一样,唯一的不同就是删除的内容是后缀。
 
${parameter/pattern/string}
${parameter//pattern/string}
    经过扩展处理后的word被看作是一个pattern (这种pattern的详细描述可以见3.5.8文件名expansion). 扩展的结果就是Parameter值中符合pattern的部分被替换为string ,第一种写法,只有第一个匹配的部分被替换,第二种形式会替换parameter值中所有符合pattern的部分.如果pattern是以`#'开头的话,则pattern必须匹配parameter值的头部,如果pattern以`%'开头的话,则必须匹配parameter值的尾部。如果string 没有指定的话,被匹配的部分就会被删除,同时pattern后的那个/也是可以省略的。如果parameter指定的是`@' or `*',那么就会挨个处理每个positional parameter,然后把处理后的结果组成一个列表作为整个扩展的结果。同样的处理也应用在parameter被指定为数组的时候.
 
 

 3.5.4 命令替换
命令替换的结果是用命令的输出来替换命令的本身。命令替换的形式如下
$(command)
或者
  
`command`
Bash会把执行command并且把他的标准输出作为替换的结果使用,要注意的是输出结果最后的trailing换行会被删除。内嵌得换行会得到保留,但是可能在单词分割expasion的时候被删除。$(cat file)这种形式的替换有一种比较快速的特殊写法$(< file).

在使用老式的反引用号形式的时候,反引用号在前一个字符是`$', ``', 和 `\'的时候解释为普通的反引用号字符,而不是命令替换的关键字。第一个不带反斜杠的反引用号可以代表命令替换的结束。当使用$(command)形式的时候,整个括号内的内容都是命令,没有特例。
命令替换可以嵌套,如果要使用反引用号的嵌套形式的时候,就必须把内层的反引用号用`\'转义。
如果整个命令替换出现在双引号内的话,单词分割和文件名expansion是不会发生的.
 
 3.5.5 算术expansion
算术expansion可以对算术表达式求值,并且把它作为expansion的结果.算术expansion的格式是:
  
$(( expression ))
对于expression的处理就好像把它用双引号括起来一样,不过expression内的双引号不做特殊处理。expression的每个单元都需要经过参数expansion,命令替换和引用除义3个步骤。算术替换可以是内嵌的。

在下面的章节 (见 section 6.5 Shells算术)有关于求值得具体运作规则。如果expression是非法的,Bash会输出一个消息到标准出错上并且不做任何替换。
 3.5.6 Process Substitution
在支持命名管道(FIFOs)或者'/dev/fd'的系统上可以实现Process Substitution,基本格式如下
<(list)
or
  
>(list)
开始list的运行的时候会把list的输入输出连接到一个FIFO或者某个`/dev/fd'下的文件,而整个扩展的结果就是把这个文件的文件名作为参数传递给当前的命令。如果使用>(list)的话,写入这个文件的内容,就会作为list的输入。而如果使用<(list)的话,那么list的输出就可以从这个文件中读到。注意<,>与左括号之间是没有空格的,否则的话会被解释成为重定向操作
在允许的情况下 process substitution和参数,变量expasion,命令替换和算术expasion一起被执行。
 

3.5.7单词分割
shell对没有被双引号引用的参数expansion,命令替换和算术expansion的结果进行扫描,然后进行单词分割处理。
shell把$IFS的每个值作为分隔符,然后根据这些分隔符来进行单词分割。如果$IFS是unset,或者值正好是默认值<space><tab><newline>的情况下,那么就严格的用这几个字符来进行分割。在$IFS的值不是默认值的情况下,只要$IFS中有whitespace/tab之类的空格字符的话,那么被解析的字符串中开头和结尾的空格字符都会被忽略,而$IFS中除了空格字符之外的那些字符,会被当作分隔符来使用。也就是说一串空格字符会被当作一个分隔符号来处理。如果$IFS的值为null的话,则不会产生分割效果。
Explicit null arguments ("" or ") are retained. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed. If a parameter with no value is expanded within double quotes, a null argument results and is retained.
明示的null参数(""或者")被保留(不被解析?)。没有被引用起来的的隐示null参数,由参数expansion 返回出来的没有值得结果,都被删除。如果没有值的参数用双引号引用起来的话,null参数被求值并且被保留。
注意如果没有发生expansion 的话就不会产生单词分割。
9 avril

我的翻译计划:Bash参考手册 第三章 基本功能 (3)

3.3 shell函数
shell函数提供了把命令组织起来用一个名字来执行的方法。这些命令执行起来就像一个普通的命令,当函数名被当成一个简单的命令名称来使用的时候,和这个函数名关联一系列命令就会被执行了。shell函数是在当前的shell上下文中执行的,而不会创建新的进程去解析他们。

函数以下面的语法来声明。
[ function ] name () { command-list; }

这个语法定义了一个shell函数名字叫做name,保留字function可写可不写。如果写了function,那么圆括号就是可选的,函数的主体是用{和}括起来的命令队列。当name被指定的时候这个命令队列就会被执行。函数的退出状态就是函数内最后被执行的命令的退出值。

注意,因为历史原因,函数主体的外的花括号必须和主体之间用blanks或者newlines隔开。这是由于花括号是保留字,必须在被空格分隔的时候才能被正确的识别。同样的,命令列表必须由一个分号或者newline 结尾。

当一个函数执行的时候,函数的参数在执行的过程中会变成positional parameters (见3.4.1positional parameters )。代表positional parameters个数的特殊的参数`#'会被更新以便反映positional parameters的变化。positional parameters 0 是不会改变的,当函数执行的时候函数名会被设置到变量FUNCNAME 上。

如果函数内执行过程从遇到了内建命令return ,则整个函数就结束了,并且开始执行函数调用后的代码。当函数结束运行后,positional parameters 和`#' 的值就会被恢复成调用函数前的值。如果return 带有一个数值参数的时候,那么这个参数就带表了函数的返回值。否则的话函数的返回值是在return 之前最后被执行命令的退出值。

函数本地变量可以用内建的local来声明。这些变量的可见范围仅限于函数内部。

函数可以是递归的,而且是可以无限的递归。


3.4 Shell 参数
3.4.1 Positional Parameters    shell的命令行参数
3.4.2 特殊参数    Parameters with special meanings.

参数是一个存放值的实体。他可能是一个名称,一个数值,或者下列的任何一个特殊的字符
。因为shell的原因,一个变量是一个用名称来标示的参数。一个变量有他的值和0个或者多个属性。用内建命令declare可以调整变量的属性(见4.2 Bash内建命令)。

一个变量在分配一个值的同时被设置(set)。null字符串也是可以作为值的。当一个变量是被设置状态的时候,可以用unset命令来使它处于非设置状态。

变量可以用以下的形式赋值
name=[value]

当value没有指定的时候,变量就被赋值为null字符串。所有的变量都要经过波折号expansion,参数和变量expansion,命令替换,算术expansion和引用除义(下有详述)几个步骤。如果变量的integer 属性被设置的时候,即使不用$((...)) ,变量的值也会经过算术expansion 的处理(见 3.5.5 算术expansion )。下述的"$@" 在被explained后,单词分割步骤不会被执行。文件名expansion 也不会被执行。赋值语句可以跟随在内建命令declare, typeset, export, readonly, 和local 后。

3.4.1 Positional Parameters
Positional Parameters是一些用一位或者一位以上数字来标示的的参数,其中不包括以单个0标示的参数。Positional parameters 在shell被

调用的时候,从shell的命令行参数传入,也可以用内建命令set来重新赋值。可以用${N}来引用 Positional parameter N ,当N只有一位数字

的时候也可以用$N来标示。 Positional parameter不能直接用赋值语句来赋值,必须使用内建的set 和shift命令来操作(见 4. Shell内建命

令)。在执行函数的时候,Positional Parameters会被临时的替换掉(见3。3shell 函数).

如果Positional Parameters的标示符表包括了超过一位以上数字的时候,必须用花括号括起来。

3.4.2 特殊参数
shell 自带了许多特殊的参数,这些参数只能引用而不能赋值。

*
 扩展成为所有positional parameters 的列表。当出现在双引号内的时候,它被解释为包含了"用特殊变量IFS的值的第一个字符分割的positional parameters列表"的单个word。这就意味着,"$*" 等价于 "$1c$2c...",其中 c 是IFS变量的值的第一个字符。如果IFS没有被设置的时候,c就是一个space。如果IFS的值是空字符串的时候,positional parameters是不带间隔的排列的。

@
 扩展成为所有positional parameters 的列表.当出现在双引号内的时候,每个positional parameters都被扩展为单个word .也就是说 "$@"就相当于$1" "$2" ....当没有positional parameters 的时候 "$@" 和 $@ 是没有作用的(他们会被直接删除)

#
 扩展为用十进制表示的positional parameters数量

?
 扩展为最后一个在前台执行完成的命令(管线)的退出值。

-
 (连字号)扩展为当前的选项 flags ,这些flags可以用set设置或者在调用shell的时候用命令行参数设置(比如-i选项).

$
 扩展为shell的进程ID。在() subshell的情况下,仍旧代表()外部代码shell的进程ID而不会代表subshell的进程ID.

!
 扩展为最后一个以background (异步)方式运行命令的进程ID.

0
 扩展为shell或者shell script 本身的名称.这个值在shell初始化的时候被设置。如果带一个命令文件的参数来调用bash 的时候(见3.8 shell 脚本),$0 被设置为这个命令文件的名字。如果指定选项-c 来调用(见6.1 调用bash),$0被设置为将被执行的字符串后面的第一个参数(如果有的话)。如果没有这个参数的话,它被设置为调用bash 用的文件名。

_
 (下划线)当一个shell启动的时候,会被设置成shell或者shell script的绝对文件路径。随后,会被扩展为上个被执行命令的最后一个参数。或者设置为每个要执行的命令的绝对路径名,并且export到这个要执行的命令的环境里面去。在检查mail信息的时候,这个参数保存了现在正在查看的mail的文件名。

2 avril

我的翻译计划:Bash参考手册 第三章 基本功能 (2)

2007/3/25整理后

3.2 Shell的命令

一个单一命令(比如 echo a b c)是由命令本身和后续的若干参数组成的,它们之间使用空格分隔。

单一命令通过各种方式组合可以生成复合命令。其中包括用管线让一个命令的输出成为另外一个命令的输入,或用循环/条件表达式进行逻辑上的组合等等。

3.2.1 单一命令    最通用的一些命令.
3.2.2 管线    连接几个命令的输入输出.
3.2.3 串接命令    有序的执行若干命令.
3.2.4 循环    用来执行重复任务的命令.
3.2.5 条件选择    用命令实现条件选择.
3.2.6 命令组    如何把命令组合起来.


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.2.1 单一命令

单一命令是我们接触最多的命令了。它是由一个用空白(blank)分隔,并以某个控制符(见 2 定义)结尾的单词序列。第一个单词通常用来指定要执行的命令,而其余的单词就成了命令的参数。

通常情况下单一命令的返回码(见 3.7.5 退出码)就是它的退出码(可通过POSIX 1003.1 的 waitpid 函数取得)。而当这个单一命令是被信号n中止的时候,返回码的值是128+n.


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.2.2 管线

管线是一些由`|'(*1)分隔的单一命令组成的序列。 (*1 译注:也就是我们常说的管道操作符或者简称管道,这里把原文的pipeline翻译成管线是为了代表管道符+命令的组合体)

管线的格式如下

 
[time [-p]] [!] command1 [| command2 ...]

每个管线中的命令的输出都通过管线连接到了下个命令的输入上。也就是说每个管线中的命令都读取上个命令的输出。

保留字 time 的作用是在管线执行后,打印出它的时间统计数据。统计数据包括命令执行总共使用的时间、用户指令执行时间和系统指令执行时间。使用参数`-p' 可以把输出格式指定为POSIX的标准格式。使用TIMEFORMAT变量可以定制time的输出格式(见5.2 Bash的变量,这个章节有关于TIMEFORMAT设定方法的详细描述)。为了可以分析Shell内置命令、Shell函数和管线执行的时间数据,所以把time设计成了Shell的保留字。因为一个外部的time命令要实现这些功能不是这么容易的。

当管线以非异步方式(见 3.2.3 串接命令)执行时,Shell会一直等到管线中所有的命令完成。

每个管线中的命令都是在自己的子shell里面执行的(见 3.7.3 命令执行时环境).整个管线的退出码等于管线中最后一个命令的退出码 。如果在管线头部指定了保留字 `!',则整个管线的退出码就是最后一个命令退出码逻辑取反后的值。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.2.3 串接命令

一个或者多个由单一命令组成的管线`;', `&', `&&', 或者 `||'连接起来形式称之为串接命令。在某些情况下需要用`;', `&', 或者一个newline来结束整个串接命令。

这些串接命令用的操作符中 `&&'`||'具有相同的、较高的优先级,而`;'`&'则具有相同的、较低的优先级。

一个或者多个newlines可以用来分隔被串接的命令,分号也有相同的效果。

一个以`&'结尾的命令会在一个子shell内以异步的方式执行。这个方式通常被称为后台(background )运行。异步命令开始运行后Shell会立即以返回码0(真)返回,而不会真正去等待命令执行完毕. 如果没有激活作业控制功能的话(见7.作业控制) ,默认情况下,异步命令的标准输入会被定向为/dev/null.

`;'连接起来的命令按顺序被执行;Shell等待每个命令结束然后再启动下一个命令。并返回最后一个被执行的命令的退出码。

控制符`&&'`||'分别表示的关系。 串接的写法如下。

 
command1 && command2

当且仅当 command1以0作为退出码返回的时候command2才会被执行。

串接的写法如下。

 
command1 || command2

当且仅当 command1以非0值作为退出码返回的时候command2才会被执行。

整个/串接命令的返回码是最后被执行的命令的退出码。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.2.4 循环

Bash 支持如下的循环结构。

注意:下面描述的代码中,任何出现`;'的地方都可以用一个或者多个newline来代替。

until
until 命令的语法如下:
 
until test-commands; do consequent-commands; done
执行consequent-commands 直到test-commands的退出码为0。 整个循环的返回码会被设置成最后一次被执行的consequent-commands的退出码,如果consequent-commands一次也没有被执行的话,返回码就是0.

while
while 命令的语法如下:
 
while test-commands; do consequent-commands; done

执行consequent-commands 直到test-commands的退出码为非0.整个循环的返回码会被设置成最后一次被执行的consequent-commands的退出码,如果consequent-commands一次也没有被执行的话,返回码就是0.

for
for 命令的语法如下:

 
for name [in words ...]; do commands; done
展开words ,并且为展开后的结果列表内每个项目执行一次commands,执行的时候name会绑定到当前的项目.如果没有指定`in words',for会为每个命令行参数(*1) 执行一次commands,就如指定了`in "$@"'的效果一样(见3.4.2 特殊参数)。for也是把最后执行的命令的退出码作为自己的返回码的。如果展开的结果是空列表的话,没有任何命令会被执行,同时整个命令返回0。 (*1就是$1,$2....)

for 还有另外一种形式:

 
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done
首先,算术表达式expr1 根据后述(见6.5Shell算术)的规则运行一次。然后,算术表达式expr2反复被运行直到结果为0,每次expr2运行的结果为非0的时候,commands和算术表达式expr3就会依次各运行一次。任何被省略的表达式都会被替换为恒值`1'。整个命令把最后一个执行的command的退出码作为自己的返回码。当任何算数表达式非法的时候,返回码为false。

内置命令 breakcontinue (见4.1 Bourne Shell内置命令 )可以用来控制循环的执行。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.2.5 条件选择

if
if 命令的语法是:

 
if test-commands; then
  consequent-commands;
[elif more-test-commands; then
  more-consequents;]
[else alternate-consequents;]
fi

首先test-commands被执行,如果返回码为0的话就执行consequent-commands。如果test-commands返回非0的话,elif 会被依次执行,当某个elif的退出码为0的时候,对应的 more-consequents 就会被执行,并且整个命令结束。如果`else alternate-consequents' 存在, 并且所有的if/elif 都返回了非0的值得话,alternate-consequents 就会被执行。最后一个执行的命令的退出码就是整个命令的返回码。当没有任何命令被执行的时候返回码为0.

case
case 的语法如下:

 
case word in [ [(] pattern [| pattern]...) command-list ;;]... esac

case会执行第一个够成功匹配word的pattern所在 分支的command-list .`|' 是用来分隔一个分支里的多个patterns的,而`)'操作符则是这个分支的pattern列表的结束符。如上所述,一个分支是由一个pattern列表和一个关联的command-list组成的。每个分支必须用 `;;'来结尾。word会经过展开波浪号,展开参数,命令替换,展开算式,和清除转义符处理后才能被用来进行匹配。而每个 pattern需要经过的步骤是展开波浪号,展开参数,命令替换和展开算式处理。

case可以拥有任意数量的分支。第一个可以匹配word的pattern决定了那个 command-list可以被执行。

下面是个例子,在一个脚本中使用case来表述某个动物的某个特点:

 
echo -n "Enter the name of an animal: "
read ANIMAL
echo -n "The $ANIMAL has "
case $ANIMAL in
  horse | dog | cat) echo -n "four";;
  man | kangaroo ) echo -n "two";;
  *) echo -n "an unknown number of";;
esac
echo " legs."

如果任何pattern都没有被匹配,返回码是0。否则返回码就是最后执行的command-list的退出码。

select

select可以方便的生成菜单,它的语法基本上和for 命令一样:

 
select name [in words ...]; do commands; done

in后面的words列表会被展开,并生成一个项目列表。每个项目都被加上一个数字前缀后输出到标准错误输出流上,如果省略`in words'的话,命令行参数就会被输出,就好像指定了`in "$@"'一样。接下来会显示PS3提示符,并且从标准输入中读取一行。如果读入内容正好是某个word所对应的数字的话。那么name的值就会被设置成那个对应的word.如果读入的是空行的话,那么项目列表和提示符就会重新显示一次。如果读入了EOF的话,select命令就自动结束了。所有其他的输入都会导致name被设置为null。被读入的行储存在变量REPLY中。

每次选择某个项目后对应的commands都会被执行并重新打印列表并等待输入,用 break命令可以结束整个循环。

下面是个例子,它允许用户从当前目录中选取一个文件名,并且显示选中的文件名和索引(就是数字前缀)。

 
select fname in *;
do
	echo you picked $fname \($REPLY\)
	break;
done

((...))
 
(( expression ))

根据后叙(6.5Shell算术)的规则运算算术表达式expression ,如果求出得值为非0的话,返回0;否则的话就返回1。作用就和

 
let "expression"
一样。 详细的关于let的描述见4.2 Bash内置命令.

[[...]]
 
[[ expression ]]

根据条件表达式expression返回0或者1,expression是由在6.4 Bash条件表达式 中介绍的元件构成的。在 `[['`]]'内的单词在处理的时候不会经过单词分解和展开文件名这两个步骤。而展开波浪号,展开参数/变量,展开算式,命令替换,管道置换,和清除转义符的步骤都会被执行。

当使用`=='`!='操作符时,操作符右边的字符串被视为一个模式,按照下面在 3.5.8.1 模式匹配中描述的规则进行匹配。如果字符串匹配该模式,返回码为 0,否则返回 1。模式的任何部分都可以被转义,以强制它作为字符串被匹配。 (这一整段主要由ma3r提供翻译)

表达式可以用以下的操作符组合起来,注:下面这个列表是按照优先度的降顺排列的:

( expression )
返回expression的值,主要是用来改变优先级用的。

! expression
取反。

expression1 && expression2
如果 expression1 和expression2都为真的时候返回真。

expression1 || expression2
expression1或expression2任意一个为真的时候返回真。

在使用&&||操作符的时候,如果根据expression1的结果足以判断整个表达式的结果的时候,expression2不会被执行。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.2.6 命令组

bash提供了2种把许多命令组合起来执行的方法。当命令被组合起来的时候,重定向处理就可以被同时使用在多个命令上了。举例来说,所有命令的输出可以被重定向到某个指定的流中。

()
 
( list )

当命令列表list被圆括号括起来的时候,会导致一个子shell被创建,所有list中的命令都会在那个子shell里面被执行。由于在子shell中执行,变量赋值等操作在子shell结束后不会留下任何影响。

{}
 
{ list; }

把命令列表list用花括号括起来的时候,会使这些命令在当前的shell环境中执行而不会创建子shell.每个list 中的命令都必须以分号(或者是newline)结尾。

还有一点补充说明的是,由于历史原因圆括号和花括号机制之间有微妙的不同,花括号是保留字,所以和内部的list之间必须用空格分隔开。而圆括号是个操作符,即使他和list之间没有空格的话也能被正确的分隔开。

这两种命令组的退出码都是list的退出码。

23 mars

我的翻译计划:Bash参考手册 第三章 基本功能 (1)

2007/02/27 整理后版本

 注意:手册中的超链接是无效的,当完全翻译完后会提供一个能够使用超链接的html版本。

3. 基本功能

bash是`Bourne-Again SHell'的缩写,Bourne shell 是由Stephen Bourne开发的运行在老版本Unix上的shell。所有的Bourne shell的内建命令都在Bash中实现了,而求值(evaluation )和转义的规则则遵循了POSIX 1003.2规范(这个规范试图描述"标准"的unix)。

这个章节简短的总结了shell的基本元素:命令,控制结构,函数,参数,展开处理,重定向(用来把输出转向文件或者把文件转向输入),以及命令的执行。

3.1 Shell的语法    你的输入对于shell意味着什么.
3.2 Shell的命令    有哪些类型的命令你可以使用.
3.3 Shell的函数    如何把命令用函数来组织起来.
3.4 Shell的参数    特殊的shell变量.
3.5 Shell的展开处理    Bash如何对变量进行进一步的解释和其他多种类型扩充.
3.6 重定向    控制输入输出的流向.
3.7 执行命令    告诉你当你运行一个命令的时候发生了什么.
3.8 Shell的脚本    运行由很多命令组成的脚本文件.


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1 Shell的语法

3.1.1 Shell的内部操作步骤    shell在执行命令时做了些什么.

3.1.2 转义    如何除去某些字符的特殊含义.

3.1.3 注释    怎么写注释.

Shell是分几个步骤来读取输入的。当读到注释符(`#')的时候,shell就会忽视它及该行内余下的内容。 在其他情况下,shell会分析输入内容并把他们分成单词和操作符,并采用转义机制来确定每个单词和字符的确切含义。

接下来,shell解析这些记号(*1)把它们归类为命令或其他的有意义的组成部分、除去某些单词和字符的特殊含义后对其余单词和字符进行扩充(*2)、在需要的情况下重定向输入和输出、执行命令并且等待它返回退出码,最后把退出码保留下来供以后使用。 (*1 译注:就是上段所说的单词和字符,见第2章 定义) (*2 译注: 这里说的除去特殊含义和扩充都是展开处理的一部分,展开处理也可能减少文本的字符数)


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.1 Shell的内部操作步骤

下面简短介绍了shell在读取和执行命令时候的操作步骤。基本上,shell是这样做的:

  1. 从文件(3.8 shell的脚本)、从一串由参数`-c'(见6.1调用Bash)指定的字符串、或者从用户终端读取输入。

  2. 根据在3.1.2说明的转义规则把输入分割成单词和操作符。这些记号都用元字符分隔开。别名展开也是在这个步骤进行的(见6.6别名)。

  3. 把上一步得到的记号解析成各种复杂(译注:包括了各种流程控制和管线操作)或者简单的命令。(见3.2 Shell的命令)

  4. 依次执行各种展开处理(见3.5 Shell的展开处理),把上一步得到的记号转换成文件名(见 3.5.8 文件名展开)、命令和参数的列表。

  5. 根据上一步操作得到的参数列表执行必要的重定向操作(见3.6重定向),然后把重定向操作符及其参数从参数列表中删除。

  6. 执行命令 (见3.7 执行命令).

  7. 选择性的等待命令的结束并且获取它的退出码(见3.7.5 退出码)


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.2 转义

3.1.2.1 转义字符    如何去除单个字符的特殊含义.
3.1.2.2 单引号    如何彻底去除一串字符的特殊含义.
3.1.2.3 双引号    如何去除一串字符中大部分的特殊含义.
3.1.2.4 ANSI-C 转义    如何使用一些和ANSI-C相同的转义操作.

3.1.2.5 本土化翻译    如何把字符串翻译成不同的语言.

转义功能经常用来去除一些特定的字符和单词对shell具有的特殊含义。这个功能可以用来禁止shell对特殊字符的特殊处理,这样就让保留字在必要的时候能够作为非保留字来使用,同时还可以防止不需要的展开处理。

每个元字符(见2. 定义)对于shell 都具有特别的含义,所以当希望元字符作为单纯的字符/单词出现的时候就需要使用转义功能了。举例来说,当履历展开功能开启时,如果不希望履历展开用字符(通常是`!')产生效果的时候就需要把该字符转义,这样他就被能作为一个普通的感叹号来使用了。参阅 9.1 Bash履历功能 ,可以获得关于履历功能的详细描述。最后,转义共有3种方法,转义字符,单引号和双引号。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.2.1 转义字符

Bash使用反斜杠 `\'来作为它转义字符。它可以使后续的一个字符保持单纯文字上的意义,不过newline是个例外。如果\newline(译著:\newline(就是指输入一个\接一个回车)出现的时候,反斜杠本身就产生了特殊的含义,\newline代表的是续行功能(也就是意味着\newline会自动被从输入流中删除并对于最终的命令执行没有任何影响)。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.2.2 单引号

由单引号(`'') 引用的任何字符都保持了它们文字上的意义,但是不允许任何其他的单引号出现在其中,即使这个单引号前面有一个转义字符`\'。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.2.3 双引号

由双引号(`"')引用的字符也能保持它们文字上的意义,但是存在着例外,他们是`$', ``', 和 `\'。其中`$', ``' 在被双引号引用的时候总是保持他们特殊的含义(见3.5 Shell的展开处理),反斜杠`\'只在后一个字符是`$', ``', `"', `\', 或者 newline的时候才会展现它的特殊含义(特殊含义就是作为一个转义字符,使后续字符保持了单纯的文字上的含义)。所以说,被双引号引用的字符串里可以包括一个或多个前面带有反斜杠的双引号.

还有2个作为特别参数的字符`*'`@'也在被双引号引用的时候具有特殊意义(见3.5.3 Shell参数的展开).


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.2.4 ANSI-C 转义

shell对于具有$'string'形式的单词有特殊的处理。主要根据ANSI C标准把带有反斜杠的字符替换成相应的字符串string,规则如下(译注:下面的还是留着英文看起来方便,相信大家应该都很熟了):

\a
alert (bell)
\b
backspace
\e
an escape character (not ANSI C)
\f
form feed
\n
newline
\r
carriage return
\t
horizontal tab
\v
vertical tab
\\
backslash
\'
single quote
\nnn
the eight-bit character whose value is the octal value nnn (one to three digits)
\xHH
the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)
\cx
a control-x character

替换后的结果是不带`$'、被单引号引用的字符串。


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.2.5 本土化翻译

(*1 TODO:这一小节由于没有没有试验过,有些内容是根据英文直译的,有错误请各位看官多多包含。) 由带有`$'前缀并且用双引号引用的字符串会被根据当前的本土化(locale)设定进行翻译。如果本土化设置是C或者POSIX的话,`$'会被忽略。如果产生了翻译的效果的话,翻译的结果是由双引号引用的字符串。

一些系统用shell变量LC_MESSAGES来确定当前使用的字典(message catalog).另外一些系统则是使用shell变量TEXTDOMAIN,还有可能带有后缀`.mo'。如果你使用TEXTDOMAIN的话,你需要把TEXTDOMAINDIR 设置成字典文件的路径。还有一些系统综合了两种系统的方案,用TEXTDOMAINDIR/LC_MESSAGES/LC_MESSAGES/TEXTDOMAIN.mo这样的顺序来确定字典文件.


[ < ] [ > ] [ << ] [ Up ] [ >> ] [Top] [Contents] [Index] [ ? ]

3.1.3 注释

当shell运行在在非交互模式,或者运行在交互模式下且用内置命令shopt(见 4.2 Bash的内置命令)打开了interactive_comments选项的时候,以`#' 开头的单词能够使shell忽略这个单词本身以及同一行内其后续的所有字符。当shell运行在交互模式下且interactive_comments无效的时候,是不能够使用注释的。默认的情况下,interactive_comments在交互模式的时候是有效的。 6.3 交互式 Shell 对shell的交互模式进行了详细地说明。

19 mars

我的翻译计划:Bash参考手册 第二章 定义

2007/2/25:整理后版本

 注意:手册中的超链接是无效的,当完全翻译完后会提供一个能够使用超链接的html版本。

2. 定义

下面的定义的这些术语在本手册剩余的章节中通用.

POSIX
由基于UNIX的、关于构建可互相兼容系统的若干规范组成的规范组。Bash主要是遵循了POSIX 1003.2中的Shell规范与Tools规范。

空白(blank)   
一个空格或者一个tab字符

内置命令
一个在shell内部实现的,而不是通过外部可执行程序实现的命令。

控制符
一个具有控制功能的单词(译注:不是指英文字母组成的英语单词),包括一个newline或者`||', `&&', `&', `;', `;;', `|', `(', `)'中任意的一个。 (译注:为了和Bash本身使用的引号区分开,原文中所有的引用都采用了`被引用的内容'的形式。)

退出码
由被调用的命令返回给它的调用者的值。由于这个值必须是个8位2进制的数字,所以最大可能的返回值是255。

字段   
经过某种shell展开(*1)处理后得到的文本的基本单位。比如在用户需要执行命令的情况下,经过展开处理后得到的一个或者多个字段就被认为是需要执行的命令名和参数。 (*1 译注:是指shell在接受输入文本后,根据一定的规则替换输入文本中一部分的文字 的处理。经过多次不同类型的展开后,最终形成的文本 才会被用于执行真正的操作。比如`ls ~'最终会被替换为`ls /path/to/user/home'。)

文件名
可以标识文件的字符串。

作业   
一组进程,包括连接他们的管线和由他们派生的并且存在于同一个进程组内的子进程。

作业控制
允许用户自由的停止(暂停)或重起(继续)任何一个进程的一种机制。

元字符
在本身没有被转义的情况下,用来分割单词的字符。包括空白`|', `&', `;', `(', `)', `<', `>'.

名称   
由字母,数字和下划线组成的,而且只能由字母和下划线开头的单词名称通常用来作为shell的变量名和函数名。有时候也叫作标识符(identifier).

操作符
具体是指控制操作符重定向操作符,见3.6重定向,里面有关于重定向操作符的列表.

进程组
由具有相同的进程组ID的进程组成的集合。

进程组ID
进程组在其存活期内的标识符。

保留字
对shell具有特殊意义的单词,大部分这样的单词都使用在流程控制中,比如forwhile.

返回码
退出码的同义词.

信号   
由操作系统内核把系统中发生的某些事件通知给进程的机制.

标准内置命令
由POSIX 1003.2标准定义的内置命令。

记号(token)   
被shell认为是最小单位的一个字符序列。可能是个单词或者是个操作符

单词   
指除了操作符以外的记号...

18 mars

我的翻译计划:Bash参考手册 第一章简介

2007/2/25 整理后版本

 注意:手册中的超链接是无效的,当完全翻译完后会提供一个能够使用超链接的html版本。

1. 简介

1.1 Bash是啥?    简短的介绍了Bash.

1.2 Shell又是啥?    简短的介绍了shells.

1.1 Bash是啥?

Bash是一个给GNU操作系统使用的shell(*1),和命令语言解释器。Bash这个名字是`Bourne-Again SHell'的缩写,同时这个名字里也提到了Stephen Bourne,Unix shell /bin/sh 的早先版本的开发者,这个早先版本的shell出现在贝尔实验室unix 的第七版中。 (*1译注:一般翻译为壳,实在读起来不通顺,还是把英文留着把)

Bash基本兼容sh,并且还整合了很多Korn shell ksh和 the C shell csh里面有用的功能。bash立志于成为符合IEEE POSIX Shell 和Tools(IEEE Working Group 1003.2) 标准的一个非常易用的实际作品.不论在交互式界面或者是可编程界面,bash对于sh都是一个超越。

虽然GNU操作系统提供了其他的很多shell,包括某些版本的csh,但是,一般来说Bash是默认的shell。和其他的GNU软件一样,Bash也是很容易移植的,现在它运行在几乎所有的Unix版本操作系统上,并且还作为独立支持(译注:原文是independently-supported 估计是有某个厂商和项目来维护的意思吧,就好像cygwin里面的bash)的移植版本运行于MS-DOS, OS/2, Windows 95/98, and Windows NT上。


1.2 Shell又是啥?

基本意义上,shell就是一个可以执行各种命令的宏处理程序。作为一个Unix shell,不但提供一种使用丰富的GNU命令的途径,还提供了一种程序设计语言,来把这些GNU 命令 结合起来使用。如果创建了一个包含其他命令的文件,那么这个文件本身也变成了命令.shell对待这些被新建的命令与对待系统原有的命令是没有区别的,比如可以把他们放进`/bin'目录,shell通过这种方法允许用户构建自定义的环境.

通过shell 可以以同步或者异步的方法来执行一个GNU 命令(译注:不知道为什么作者老是要限定GNU的command,其他的Command也是可以用的说).同步方式下,shell会等待被执行命令结束后才接受其他的输入。异步方式下的命令和shell是并行执行的,这个时候shell可以读入和执行其他的命令。重定向机制提供了对被执行命令的输入输出系统进行细密控制的手段。此外,shell还提供了操控命令执行环境 的手段。shell自己可以作为交互式或者非交互式方法运行:接受从键盘的输入或者是从文件中读取输入。

shells同时也提供了一小撮内置命令,目的在于提供那些由外置的命令不能或者较难实现的功能。举例来说,cd,break,continue以及exec 由于直接操作了shell本身,所以他们不能在shell的外部实现。history,getopts,killpwd 虽然可以外置命令来实现,不过相对来说这些常用的命令做成内置的话对用户来说比较方便。所有的这些内置命令的内容都会在后面的章节给大家说明的。

除了完成执行命令的功能以外,shell的强大性(同时也是复杂性)还体现在他内嵌的程序设计语言。和其他的高级语言类似,shell也提供了变量,流程控制,转义机制和函数。

比起普通的编程接口来说shell在交互式接口上下了更多的功夫,提供了包括作业控制,命令行编辑,履历和别名等交互式功能,这些功能都在后面章节进行了说明。

我的翻译计划:Bash参考手册 前言+目录

这些天由于工作的需要,需要查找一些bash相关的内容,可以网上竟然找不到一篇完整的翻译文档,于是考虑自己来翻译吧,一方面可以给那些需要的人提供帮助,一方面也能丰富自己的业余文化生活。翻译计划就是从今天开始不定期连载。
catalog是Bash翻译
 
2007/2/25 追记:已经翻译到了第三章结束,在翻译接下来的章节之前,准备把以前翻译的章节都重新整理一下,尽量用易懂的,没有歧义的中文表达方式来翻译。并且加上了一些html标签,和尽量统一术语便于阅读。 注意:手册中的超链接是无效的,当完全翻译完后会提供一个能够使用超链接的html版本。

这篇手册是对Bash 功能的一个简单说明。

这是Bash 参考手册2.5b版,最后更新日是2002年7月15日,对应的Bash版本是2.05b.
译者:唐礼擎 email:zebrafish2006@gmail.com Blog:zebrafish.spaces.live.com

Copyright (C) 1991-2002 Free Software Foundation, Inc.

Bash融合了许多流行的shells的功能,并加以自己的创新。Bash吸取了Bourne Shell (`sh'), Korn Shell (`ksh'), 和 C-shell (`csh' 包括他的改进版本`tcsh')的很多有用的功能。接下去的目录结构基本上是按照Bash的功能来划分章节的。

这篇手册只是为了简短的介绍bash的功能。需要完整的参考的话请参阅Bash man page.

1. 简介    把Bash介绍给大家.

2. 定义    定义了一些在本手册中通用的术语.

3. 基本功能    作为一个shell的基本功(译注:本文是The shell "building blocks".是积木的意思,在这里应该是基础把) .

4. 内置命令    作为Shell自身的一部分的那些命令.

5. 变量    由Bash设置和使用的变量.

6. Bash 特性    Bash独有的功能.

7. 作业管理    这个章节说明了什么是作业管理和在Bash下应该怎么操作.

8. 编辑命令行    这个章节告诉你如果对你输入的命令进行编辑,可以减轻你输入大段命令的烦恼。

9. 交互式的履历功能    告诉你 履历展开(译注:接下来有一些比较涩口的名词都用下划线来标示) 的规则和怎么使用它.

10. 安装Bash    如何让Bash在你的系统上安家.

A. 汇报Bug    如果你发现了Bug...

B. 和Bourne Shell的主要不同点    用一个简单列表说明了Bash和以前的版本的/bin/sh的不同点.

Shell 内置命令索引    可以根据内置命令快速的定位相关的章节.

Shell 保留字索引    可以根据保留字快速的定位相关的章节.

参数和变量索引    可以根据参数和变量快速的定位相关的章节.

函数索引    可以被绑定的Readline 函数的索引.

概念的索引    可以根据 在本手册中提出的概念 快速的定位相关的章节.