Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 脚本和下标之间的标准输出竞争条件_Shell_Stdout_Zsh_Race Condition_Io Redirection - Fatal编程技术网

Shell 脚本和下标之间的标准输出竞争条件

Shell 脚本和下标之间的标准输出竞争条件,shell,stdout,zsh,race-condition,io-redirection,Shell,Stdout,Zsh,Race Condition,Io Redirection,我试图调用一个脚本deepScript并在另一个脚本shallowScript中处理其输出;它在示意图上类似于以下几段代码: shallowScript.sh #!/bin/zsh exec 1> >( tr "[a-z]" "[A-Z]" ) print "Hello - this is shallowScript" . ./deepScript.sh #!/bin/zsh print "Hello - this is deepScript" #!/bin/zsh print

我试图调用一个脚本deepScript并在另一个脚本shallowScript中处理其输出;它在示意图上类似于以下几段代码:

shallowScript.sh

#!/bin/zsh
exec 1> >( tr "[a-z]" "[A-Z]" )
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
print "Hello - this is deepScript"
#!/bin/zsh
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
function _process {
  while read input; do
    echo $input | tr "[a-z]" "[A-Z]"
  done
}
. ./shallowScript.sh | _process
deepScript.sh

#!/bin/zsh
exec 1> >( tr "[a-z]" "[A-Z]" )
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
print "Hello - this is deepScript"
#!/bin/zsh
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
function _process {
  while read input; do
    echo $input | tr "[a-z]" "[A-Z]"
  done
}
. ./shallowScript.sh | _process
现在,当我运行./shallowScript.sh时,结果是不稳定的:要么按预期工作(很少),要么打印一个空行,后跟两行预期的行(有时),要么打印这两行,然后挂起,直到我点击return并给它换行(大部分时间)。 到目前为止,我发现了以下几点:

  • 这可能是一种竞争条件,因为两个“print”试图同时输出到stdout;在调用“./deepScript.sh”之前插入“sleep 1”可以一致地更正问题
  • 问题来自进程替换“exec 1>>(tr…);对其进行注释也可以持续地纠正问题
我浏览了太多关于进程替换和重定向的论坛和帖子,但找不到如何保证我的脚本同步调用命令。想法

zsh --version                                                                                                                                                                   
zsh 5.0.5 (x86_64-apple-darwin14.0)
[编辑]

由于这一策略似乎注定会失败或导致可怕的变通语法,下面是另一个似乎适用于可承受语法的策略:我从shallowScript.sh中删除了所有重定向,并创建了第三个脚本,其中输出处理在函数中进行:

shallowScript.sh

#!/bin/zsh
exec 1> >( tr "[a-z]" "[A-Z]" )
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
print "Hello - this is deepScript"
#!/bin/zsh
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
function _process {
  while read input; do
    echo $input | tr "[a-z]" "[A-Z]"
  done
}
. ./shallowScript.sh | _process
thirdScript.sh

#!/bin/zsh
exec 1> >( tr "[a-z]" "[A-Z]" )
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
print "Hello - this is deepScript"
#!/bin/zsh
print "Hello - this is shallowScript"
. ./deepScript.sh
#!/bin/zsh
function _process {
  while read input; do
    echo $input | tr "[a-z]" "[A-Z]"
  done
}
. ./shallowScript.sh | _process

我想问题在于执行脚本后没有看到提示:

$ ./shallowScript.sh
$ HELLO - THIS IS SHALLOWSCRIPT
HELLO - THIS IS DEEPSCRIPT
(nothing here)
我想它会挂在这里,等待新线。事实上不是这样,而且这种行为是很正常的

您可以输入任何shell命令,例如
ls
,而不是换行符,然后执行该命令

$ ./shallowScript.sh
$ HELLO - THIS IS SHALLOWSCRIPT  <--- note the prompt in this line
HELLO - THIS IS DEEPSCRIPT
echo test                        <--- my input
test                             <--- its result
$
在这里,外壳将等待
cat
过程完成,然后再打印下一个提示,
cat
仅当其所有输入(例如
tr
的输出)都得到处理时才会完成,正如您所期望的那样

更新:在以下zsh文档中找到相关报价:

>(过程)
还有一个问题;当此命令附加到外部命令时,父shell不会等待进程完成,因此紧跟其后的命令不能依赖于完成的结果。问题和解决方案与重定向中的
MULTIOS
一节中描述的相同。因此,在上述示例的简化版本中:

paste <(cut -f1 file1) <(cut -f3 file2) > >(process)
在您的情况下,它将给出如下内容:

{
        print "Hello - this is shallowScript"
        . ./deepScript.sh
} 1> >( tr "[a-z]" "[A-Z]" )

这当然有效,但看起来比原来的更糟。

谢谢,解释很有道理。只是一个问题,我应该考虑“猫”的伎俩,像解决方案还是像一个转身?它似乎不容易推广,每次我从交互式shell调用脚本时都要记住它,感觉有点尴尬。这绝对是一种解决方法,不能用于日常脚本编程。一般规则应该是,不要编写让孩子在父母去世后继续写作的脚本。在您的特定情况下,为什么不使用普通的
重定向(例如
/shallowScript.sh | tr“[a-z]”“[a-z]”“
)将输出传递到
tr呢?因为在我的实际脚本中,我的下标的处理比简单的re要长得多,这也是因为进程替换使得语法非常优雅。使用相关zsh文档的链接更新了答案。
…>>(…)
只是一个简单的管道,相当于
…|。仅当需要对文件进行写访问时,才需要进行进程替换。与
tee
一起使用是常见的:
…|tee>(…)>(…)
,其中
tee
需要文件名作为参数。不需要
\u进程中的while循环<代码>_进程(){tr“[a-z]”“[a-z]”;}
tr
将已经处理其标准输入的每一行,因此无需为函数的标准输入的每一行调用它一次。True;我使用
tr
制作了一个易于理解和测试的代码片段,但我的真实脚本尝试做的不仅仅是
tr