• 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)或是外部程序。
  • 相关阅读:
    1、编写一个简单的C++程序
    96. Unique Binary Search Trees
    python 操作redis
    json.loads的一个很有意思的现象
    No changes detected
    leetcode 127 wordladder
    django uwsgi websocket踩坑
    you need to build uWSGI with SSL support to use the websocket handshake api function !!!
    pyinstaller 出现str error
    数据库的读现象
  • 原文地址:https://www.cnblogs.com/fly-xiang-zhao/p/3675642.html
Copyright © 2020-2023  润新知