【问题标题】:Avoid subshell from pipe on dash避免破折号上管道的子壳
【发布时间】:2016-07-16 01:47:31
【问题描述】:

我有这个示例代码:

find "$1" ! -regex "$regex" 2>/dev/null | while read line ; do
    a="$line"
done

echo ("$a") # prints nothing because of subshell

我需要:

  • 子shell 使$a 在外部可见(在全局范围内)的解决方法
  • 不使用 bash 的进程替换
  • 兼容 dash、bash 和 korn shell

我怎样才能做到这一点?有没有简单的解决办法?

【问题讨论】:

    标签: bash pipe ksh dash-shell subshell


    【解决方案1】:

    如果我对您的理解正确,那么困扰您的不是子shell,而是变量在子shell之外没有保留其值的事实。 您可以像这样使用代码分组:

    find "$1" ! -regex "$regex" 2>/dev/null | 
    { 
      while read line
      do
        a=$line
      done
      echo "$a"
    }
    

    您可以使用变量a 的值,只要它位于花括号内即可。

    【讨论】:

      【解决方案2】:

      如果没有命名管道,也无需在子 shell 中运行整个内容,您可以在 here-doc 中使用 here-doccommand substitution

      while read line; do
          a=$line
      done <<EOF
          $(find "$1" ! -regex "$regex" 2>/dev/null)
      EOF
      
      echo "$a"
      

      这应该是可移植的。

      另请参阅。 BashFAQ/024

      注意。像这样解析find 的输出是一种反模式。

      【讨论】:

        【解决方案3】:

        使用显式命名管道。

        mkfifo named_pipe
        find "$1" ! -regex "$regex" 2> /dev/null > named_pipe &
        
        while read line; do
            a=$line
        done < named_pipe
        

        【讨论】:

        • 有什么办法可以避免创建文件吗?我们不能制作临时文件:S
        • 不怕。您唯一的其他选择是将find 的调用替换为使用for 循环遍历当前目录层次结构中的所有文件的shell 函数(递归,如果您需要下降到子目录)。 expr 可用于再次检查每个文件是否符合正则表达式,或者如果正则表达式不太复杂,您也可以使用文件名模式。
        • 好吧,不管怎样,它工作得很好,所以标记为已解决。非常感谢! :)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-08
        • 1970-01-01
        • 2018-12-04
        • 1970-01-01
        • 2013-10-09
        • 1970-01-01
        • 2018-07-13
        相关资源
        最近更新 更多