分享

linux中的组命令和子shell

 ala咪s 2017-08-16
 
 

组命令和子shell

在bash中,有两种方式可以将命令组合到一起,一种是组命令,另一种是子shell。格式如下:

# 组命令
{ commnad1; command2; [ command3.. ] }
# 子shell
(command1; command2; [command3..])
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

上面两种形式的差别在于:1.组命令使用花括号括起来,前花括号和后花括号与命令之间要有一个空格,并且闭合花括号前要用分号或换行结束命令。2.对于子shell,只需要用圆括号包围即可。

执行重定向

那么,组命令和子shell有什么用途呢?尽管它们有一个主要的区别,但是它们都可以用来管理重定向。下面请看这个例子:

[fbap:/home/fbap/usertmp]>ls -l > output.txt
[fbap:/home/fbap/usertmp]>echo "hello world" >> output.txt
[fbap:/home/fbap/usertmp]>cat foo.txt >> output.txt
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

显然,上面的3条命令将输出重定向到output.txt。使用组命令,可以将它们合并成一行:

{ ls -l; echo "hello world"; cat foo.txt; } > output.txt
  • 1
  • 1

当然,你也可以使用子shell的方式:

(ls -l; echo "hello world"; cat foo.txt;) > output.txt
  • 1
  • 1

在上面的例子中,使用组命令和子shell可以减少一些输入。但是,组命令和子shell真正有价值的地方在于管道的使用。当创建命令管道时,通常将多条命令的结果输出到一条流中,这很有用。

{ ls -l; echo "hello world"; cat foo.txt; } | lpr
  • 1
  • 1

这里,我们将3个命令的输出进行合并,并通过管道输出到lpr的输入以产生一个打印报告。

进程替换

虽然组命令和子shell看起来很相似,都可以用来为重定向整合流,但是,它们有一处主要的不同。子shell(正如其名字)在当前shell的子拷贝中执行命令,而组命令则是直接在当前shell中执行所有命令。这以为子shell会复制当前环境变量以创建一个新的shell实例。当子shell退出时,复制的环境变量也就消失了,因此对任何子shell(包括变量赋值)的改变也同样丢失了。所以,大多数情况下,除非脚本需要子shell,否则使用组命令比子shell更快,占用内存也更少。

请看下面的例子:

echo 'foo' | read 
echo $REPLY
  • 1
  • 2
  • 1
  • 2

在上面的例子中,REPLY的内容总是空的,因为read命令是在子shell中执行的,并且当子shell终止的时候,REPLY的拷贝也遭到了破坏。

很幸运的是,shell提供了一种叫做进程替换的外部扩展方式来解决这个问题。

实现进程替换的方式有两种:

# 产生标准输出的进程
<(list) 

# 吸纳标准输入的命令
>(list)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

为了解决上述read命令的问题,我们可以像这样使用进程替换:

read < <(echo "foo")
echo $REPLY
  • 1
  • 2
  • 1
  • 2

进程替换允许将子shell当成普通的文件,目的是为了重定向。事实上,这是一种扩展形式,我们可以查看它的真实值。

[fbap:/home/fbap]>echo <(echo "foo")
/dev/fd/63
  • 1
  • 2
  • 1
  • 2

通过使用echo查看扩展结果,可以看到文件/dev/fd/63正为子shell提供输出。

以下是一个读循环的实例,该实例用循环处理子shell创建的目录列表的内容:

#!/bin/bash

# 注:
#   1.如果将此处的内容另存为一个脚本如sub-proc.sh,但是如果像这样执行脚本:sh sub-proc.sh,shell将报错syntax error(语法错误)。
# 
# 正确的执行方式是:
#   1)脚本添加可执行权限: chmod u+x sub-proc.sh
#   2)使用相对(绝对)路径: ./sub-proc.sh

while read attr links owner group size date_1 date_2 year filename 
do
    cat <<EOF
        文件名:   ${filename}
        大小:     ${size}
        拥有者:   ${owner}
        属性:     ${attr}
EOF
    echo "======================="
done < <(ls -l | tail -n +2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

执行命令:./sub-proc.sh | head -n 10,得到如下输出:

[fbap:/home/fbap/usertmp]>./sub*sh|head -n 10
        文件名:   AFA_TEST_NEWADM.ixf
        大小:     4783
        拥有者:   fbap
        属性:     -rw-rw-r--.
=======================
        文件名:   all_python_files.log
        大小:     1168088
        拥有者:   fbap
        属性:     -rw-rw-r--.
=======================

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多