subShell 是一群被括在圆括号里的命令,这些命令会在另外的进程里执行。当你需要让一组命令在不同的目录下执行时,这种方法可以让你不修改主脚本的目录。
例; 将某个目录树通过管道复制到另外一个地方。
tar -cf - . | (cd /newdir; tar -xpf - )
代码块概念上与subShell相同,但是它不会建立新的进程。代码块里的命令用花括号{}括起来,且对主脚本的状态会产生影响。
子shell: 每个shell脚本都有效地运行在父shell的一个子进程中. 这个父shell指的是在一个控制终端或在一个xterm窗口中给出命令提示符的那个进程.
shell脚本也能启动它自已的子进程. 这些子shell能够使脚本并行的, 有效的, 同时运行多个子任务.
圆括号中的命令列表( command1; command2; command3; ... )圆括号中命令列表的命令将会运行在一个子shell中.
子shell中的变量对于子shell之外的代码块来说, 是不可见的. 当然, 父进程也不能访问这些变量, 父进程指的是产生这个子shell的shell. 事实上, 这些变量都是局部变量.
子shell中的目录更改不会影响到父shell.
子shell中的目录更改不会影响到父shell.父shell不受任何影响, 并且父shell的环境也没有被更改.
子shell的另一个应用, 是可以用来检测一个变量是否被定义.
[[ ${variable-x} != x || ${variable-y} != y ]] 或 [[ ${variable-x} != x$variable ]] 或 [[ ${variable+x} = x ]] 或 [[ ${variable-x} != x ]]
使用"|"管道操作符, 将I/O流重定向到一个子shell中, 比如ls -al | (command).
在大括号中的命令不会启动子shell.{ command1; command2; command3; . . . commandN; }
Here Document: 一个here document就是一段带有特殊目的的代码段. 它使用I/O重定向的形式将一个命令序列传递到一个交互程序或者命令中, 比如ftp, cat, 或者ex文本编辑器.
COMMAND <<InputComesFromHERE
...
InputComesFromHERE
limit string用来界定命令序列的范围(译者注: 两个相同的limit string之间就是命令序列). 特殊符号<<用来标识limit string. 这个符号的作用就是将文件的输出重定向到程序或命令的stdin中.与interactive-program < command-file很相似, 其中command-file包含:
而here document看上去是下面这个样子:
#!/bin/bash
interactive-program <<LimitString
command #1
command #2
...
LimitString
选择一个名字非常诡异limit string能够有效的避免命令列表与limit string重名的问题.
-选项用来标记here document的limit string (<<-LimitString), 可以抑制输出时前边的tab(不是空格). 这么做可以增加一个脚本的可读性.
结尾的limit string, 就是here document最后一行的limit string, 必须从第一个字符开始. 它的前面不能够有任何前置的空白. 而在这个limit string后边的空白也会引起异常.空白将会阻止limit string的识别.
列表结构: "与列表"和"或列表"结构能够提供一种手段, 这种手段能够用来处理一串连续的命令.
与列表: command-1 && command-2 && command-3 && ... command-n,如果每个命令执行后都返回true(0)的话, 那么命令将会依次执行下去. 如果其中的某个命令返
回false(非零值)的话, 那么这个命令链就会被打断, 也就是结束执行, (那么第一个返回false的命令, 就是最后一个执行的命令, 其后的命令都不会执行).
或列表:command-1 || command-2 || command-3 || ... command-n如果每个命令都返回false, 那么命令链就会执行下去. 一旦有一个命令返回true, 命令链就会被打断, 也就是结束执行, (第一个返回true的命令将会是最后一个执行的命令). 显然, 这和"与列表"完全相反.
与列表和或列表的退出状态码由最后一个命令的退出状态所决定。
false && true || echo false # false # 与下面的结果相同 ( false && true ) || echo false # false # But *not* false && ( true || echo false ) # (没有输出) # 注意, 以从左到右的顺序进行分组与求值, 这是因为逻辑操作"&&"和"||"具有相同的优先级. 最好避免这么复杂的情况, 除非你非常了解你到底在做什么.
进程替换
进程替换与命令替换很相似. 命令替换把一个命令的结果赋值给一个变量, 比如dir_contents=`ls -al`或xref=$( grep word datafile). 进程替换把一个进程的输出提供给另一个进程(换句话说, 它把一个命令的结果发给了另一个命令).
用圆括号扩起来的命令>(command) , <(command)启动进程替换. 它使用/dev/fd/<n>文件将圆括号中的进程处理结果发送给另一个进程.在"<"或">"与圆括号之间是没有空格的. 如果加了空格, 会产生错误
进程替换可以比较两个不同命令的输出, 甚至能够比较同一个命令不同选项情况下的输出.
comm <(ls -l) <(ls -al) diff <(ls $first_directory) <(ls $second_directory) cat <(ls -l) # 等价于ls -l | cat sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin) # 列出系统3个主要'bin'目录中的所有文件, 并且按文件名进行排序. 注意是3个(查一下, 上面就3个圆括号)明显不同的命令输出传递给'sort' diff <(command1) <(command2) # 给出两个命令输出的不同之处. while read des what mask iface; do echo $des $what $mask $iface done < <(route -n) 一个更容易理解的等价代码是: route -n | while read des what mask iface; do # 管道的输出被赋值给了变量. echo $des $what $mask $iface done # 这将产生出与上边相同的输出. 然而, Ulrich Gayer指出. . .这个简单的等价版本在while循环中使用了一个子shell, 因此当管道结束后, 变量就消失了.
Shell中脚本变量和函数变量的作用域 http://blog.csdn.net/ltx19860420/article/details/5570902
(1)Shell脚本中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止。解析:脚本变量v1的作用域从被定义的地方开始,到shell结束。调用函数ltx_func的地方在变量v1的作用域内,所以能够访问并修改变量v1。
(2)Shell函数定义的变量默认是global的,其作用域从“函数被调用时执行变量定义的地方”开始,到shell结束或被显示删除处为止。函数定义的变量可以被显示定义成local的,其作用域局限于函数内。但请注意,函数的参数是local的。
解析:函数变量v2默认是global的,其作用域从“函数被调用时执行变量定义的地方”开始,到shell结束为止。注意,不是从定义函数的地方开始,而是从调用函数的地方开始。打印命令在变量v2的作用域内,所以能够访问变量v2。
解析:函数变量v2显示定义为local的,其作用域局限于函数内。打印命令在函数外,不在变量v2的作用域内,所以能够不能访问变量v2。函数参数是local的,通过位置变量来访问。打印命令输出函数的第一个参数。
(3)如果同名,Shell函数定义的local变量会屏蔽脚本定义的global变量。
在函数被调用之前, 所有在函数中声明的变量, 在函数体外都是不可见的,当然也包括那些被明确声明为local的变量.
退出状态码
函数返回一个值, 被称为退出状态码. 退出状态码可以由return命令明确指定, 也可以由函数中最后一条命令的退出状态码来指定(如果成功则返回0, 否则返回非0值). 可以在脚本中使用$?来引用退出状态码. 因为有了这种机制, 所以脚本函数也可以象C函数一样有"返回值".
return终止一个函数. return命令 [1]可选的允许带一个整型参数, 这个整数将作为函数的"退出状态码"返回给调用这个函数的脚本, 并且这个整数也被赋值给变量$?.函数所能返回最大的正整数是255. 为了让函数可以返回字符串或是数组, 可以使用一个在函数外可见的专用全局变量.
重定向函数的stdin函数本质上其实就是一个代码块, 这就意味着它的stdin可以被重定向.
2:shell什么情况下会产生子进程 以下几个创建子进程的情况。(以下英文摘自info bash) 1:&,提交后台作业 If a command is terminated by the control operator `&', the shell executes the command asynchronously in a subshell. 2:管道 Each command in a pipeline is executed in its own subshell 3:括号命令列表 ()操作符 Placing a list of commands between parentheses causes a subshell environment to be created 4:执行外部脚本、程序: When Bash finds such a file while searching the `$PATH' for a command, it spawns a subshell to execute it. In other words, executing filename ARGUMENTS is equivalent to executing bash filename ARGUMENTS 说明:大致上子进程的创建包括以上四种情况了。需要说明的是只要是符合上边四种情况之一,便会创建(fork)子进程,不因是否是函数,命令,或程序,也不会因为是内置函数(buitin)或是外部程序。