subShell与代码块

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)或是外部程序。
原文地址:https://www.cnblogs.com/fly-xiang-zhao/p/3675642.html