【问题标题】:Bash Script Command Redirection/Reuse -- How to Accomplish Multidirectional Layered Redirection?Bash 脚本命令重定向/重用——如何实现多向分层重定向?
【发布时间】:2012-03-30 16:05:50
【问题描述】:

我很难理解命令重定向/重用...

我知道有 <(...) <(...) 方法和 $( ... && ... ) 技术用于组合输出。但我并没有真正完全理解有什么区别(我意识到(...) 会将您转储到一个新的外壳中,导致您可能会跳转目录并丢失您尚未导出的任何变量,但我不确定它如何影响一般重定向方案),在浏览以下示例和说明后,我仍然对如何进行一对多重定向感到非常困惑:
Advanced Bash Scripting Guide 1
Advanced Bash Scripting Guide 2

我自己尝试使用它主要导致“模糊重定向”错误。

例如,假设我想做一个由下面的伪代码给出的单行

    CMD 1 && CMD 2 && CMD 3 --> (1)  
    CMD 4 (1) --> (2)
    CMD 5 (1) --> CMD 6 --> (3)
    CMD 7 (2) && CMD 8 (3) --> (4)
    CMD 9 (2) --> (5)
    CMD 10 (2) (3) -->(6)
    VAR= echo (4) && echo (5) && echo (6)

或者作为流程图

CMD 1 +CMD 2 && CMD 3 
    |\
    | ---> CMD 5 ------> CMD 6-----\
    V                     /         V
    CMD 4 ----------------u--------> CMD 10
     | \                  V           /
     |   -------->CMD 7 + CMD 8      /
     V             |                /
    CMD 9          |               /
      \            |              /
       \           V             /
        --------> VAR <----------

其中输出被指定为--&gt;--&gt;(#) 给出了在另一个操作中重用的存储空间;和组合操作由&amp;&amp;给出。

我目前不知道如何在没有冗余代码的情况下在一行中执行此操作。

我想真正掌握命令重定向,这样我就可以制作一些强大的单线。

希望这已经足够清楚了...如果您需要,我可以为命令提供概念证明示例,但伪代码应该会给您这个想法。

【问题讨论】:

  • 我不明白你说有
  • 哦,也许你的意思是 'cat out3' ?
  • 我的意思是“输出”,因为
  • 有点困惑你谈论管道和重定向,但你的伪代码是关于命令替换的。
  • 是的...或者举一个更高级的例子sort &lt;(cd $CURR_DIR &amp;&amp; find . -type f -ctime $FTIME) \ &lt;(cd $CURR_DIR &amp;&amp; find . -type f -atime $FTIME) \ &lt;(cd $CURR_DIR &amp;&amp; find . -type f -mtime $FTIME) | uniq

标签: bash scripting redirect command-substitution


【解决方案1】:

回复您的评论:

sort <(cd $CURR_DIR && find . -type f -ctime $FTIME) \ 
    <(cd $CURR_DIR && find . -type f -atime $FTIME) \ 
    <(cd $CURR_DIR && find . -type f -mtime $FTIME) | uniq

可以写成(我认为更清楚)

(find . -type f -ctime $FTIME && find . -type f -atime $FTIME \
    && find . -type f -mtime $FTIME) | sort | uniq

给定三个程序,其中一个产生“a”或“z”作为输出。生成一个字符串,其中包含已排序的输出以及作为单行的唯一输出:

mkfifo named_pipe{1,2,3}; (echo z ; echo a ; echo z) > named_pipe1 & \
    tee < named_pipe1 >(sort > named_pipe2) | sort | uniq > named_pipe3 & \
    output=$(echo sorted `cat named_pipe2`; echo unique `cat named_pipe3`); \
    rm named_pipe{1,2,3}

产生sorted a z z unique a z

您可能会注意到有关此解决方案的一件事是,它被拆分,以便每个命令分组都有自己的行。我想我在这里的意思是,一个衬里可能很酷,但通常清晰度会更好。

其工作原理是使用名为 tee 和命名管道的程序。命名管道与匿名管道完全相同,例如。 cat words.txt | gzip,除了它可以从文件系统中引用(但没有实际数据写入文件系统)。请注意,写入命名管道将阻塞,直到另一个进程正在从命名管道读取。我一直无缘无故地在这里使用管道,只是为了让您了解如何使用它们。

正如其他人所说,Tee 可以将输入复制到多个输出。

【讨论】:

  • 如果我没记错的话:find example 可以通过使用简单的find ${CURR_DIR} -type f \( -ctime ${FTIME} -o -atime ${FTIME} -o -mtime ${FTIME} \) -printf "./%P\n" 来完成,而无需任何重定向或子shell,其中-printf "./%P\n" 模仿cd ${CURR_DIR} &amp;&amp; find . 部分。无需排序。无需过滤。 (我知道它没有回答最初的问题,但它 - 我相信 - 更清楚。8)
【解决方案2】:

你有几个不同的问题要解决。

  1. 您需要一个输出作为其他几个命令的输入。您可以使用tee &gt;(cmd1) | cmd2 解决此问题。看到这个答案:How can I send the stdout of one process to multiple processes using (preferably unnamed) pipes in Unix (or Windows)?

    另一种方法是创建一个文件。我通常更喜欢文件方法,因为它允许调试最终脚本。为避免造成混乱,请创建一个临时工作目录,并使用 trap "..." EXIT 删除该目录

  2. 您需要将多个命令的输出组合为单个命令的输入。在此处使用子 shell:( CMD 1 ; CMD 2 ) | CMD 3 将 1 和 2 的输出组合为 3 的输入。

  3. 您需要将上述两者结合起来。您可以create additional file descriptors,但每个只能读取一次。使用cat 组合它们并使用tee 创建副本。

这应该都是可能的,但有一个缺点:如果某些东西不起作用或出错,您将永远无法找到错误。

因此:创建工作目录并使用文件。如果你把它放入/tmp,数据将不会被写入磁盘(在现代 Linux 系统上,/tmp 是一个 ram 磁盘),这将像管道一样,除非你有大量数据,而且你会能够维护脚本。

【讨论】:

    【解决方案3】:

    在这篇文章中有某种开始回答您的问题: How can I send the stdout of one process to multiple processes using (preferably unnamed) pipes in Unix (or Windows)?

    使用 tee 和 >(命令)。但是您的示例相当复杂,很难想象没有临时存储(变量或文件)的单行解决方案,仅通过组合命令(Unix 方式,是的!)。

    我的意思是,如果您同意按顺序启动多个命令,可能会更容易(但不再是单行命令)...

    即使用更复杂的语言(比如 python)编写这种表达式也会很复杂。

    【讨论】:

    • 酷,很好的发现tee 是朝着正确方向迈出的一步......我想知道您是否可以使用更多的多流?我添加了一个图表来描述我想到的那种复杂的命令:)
    • 我不知道如何解决的部分是同时拆分(如 cmd 4 => cmd7+cmd8 AND cmd 9)和合并(VAR &3等)
    • 好吧,事实上你可以做我刚才所说的部分,使用:cmd 4 |三通 >(cmd 7 && cmd 8) >(cmd 9) > /dev/null | cmd 10. 使用这种结构,除了将 CMD 6 和 CMD 4 合并到 CMD 7 + CMD 8 之外,您可以解决部分问题。当您尝试实现某些特定的(但频繁) 使用未实现“goto”的语言进行的各种处理。当你只有 if/else 时,你必须依靠 temp vars 来存储临时状态并更改你的代码(请不要火焰战争,只是一个注释)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    相关资源
    最近更新 更多