通过 sed 过滤 stderr 时 Bash 脚本挂起

通过 sed 过滤 stderr 时 Bash 脚本挂起

介绍

我有一个bash脚本可以通过ssh.它parallel在并行版本中使用 GNU,在顺序版本中使用 for 循环。

该脚本的使用方式如下:

foreach_server "cd $dir && find -name '*.png' | wc -l"
foreach_server "cd $dir && git --no-pager status"

有时我需要访问conda环境中的可执行文件(https://docs.conda.io/en/latest/),我发现实现这项工作的唯一方法是使用交互式 shell,即bash -ic在我想要执行的命令之前使用,就像这样ssh $host bash -ic $cmd,以便加载 conda 环境。不幸的是,这会导致 上出现两条错误消息stderr,而我无法阻止:

bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell

因此,我制作了一个过滤器,sed用于删除这两行stderr并传递以下中的其他行stderr

ssh $host "$@" 2> >(sed -e "$filter1" -e "$filter2" >&2)

问题:sed 过滤器使并行版本挂起

过滤sed器在顺序版本中工作正常,但并行版本挂在脚本末尾,表明 sed 进程处于活动状态,但不执行任何操作。我怎样才能防止这种情况发生?

我怀疑问题出在进程替换上,但我确实无法诊断出问题所在。

参考脚本

#!/bin/bash
set -u

exit_trap() {
    echo "Interrupted"
    exit 1
}

trap exit_trap SIGINT

filter1='/^bash: cannot set terminal process group/d'
filter2='/^bash: no job control in this shell/d' 

hosts=("host1" "host2")  # more hosts in the real file

if [ -z ${serial+x} ];
then
    # Parallel version ==> THIS VERSION HANGS AT THE END, AFTER ALL OUTPUT HAS BEEN WRITTEN
    echo ${hosts[@]} | sed 's/ /\n/g' | parallel "echo ----- {} ----- && ssh {} \"$@\"" 2> >(sed -e "$filter1" -e "$filter2" >&2)
else
    # Serial version ==> THIS VERSION WORKS FINE
    for host in ${hosts[@]};
    do
        echo "------------------ $host ------------------"

        ssh $host "$@" 2> >(sed -e "$filter1" -e "$filter2" >&2)

        echo "--------------------------------------$(echo $host | sed 's/./-/g')"
    done
fi

答案1

与其费尽心思地尝试消除错误消息的症状,不如消除错误消息的原因。

这将为会话分配一个 tty ssh,以便可以应用终端 ioctl:

ssh -t $host "$@"

您可能需要将标志加倍-t-tt,具体取决于您实际调用该行的方式。

然而,根本问题似乎是您需要一个交互式 shell 来设置 conda 环境。几乎可以肯定,其原因是它是在~/.bashrc.您可以.明确地执行此操作,也可以提取相关命令并在脚本中使用它们。

我不熟悉conda自己,但问题如何在 .bashrc 中激活 conda 环境?~/.bashrcAskUbuntu 上似乎引用了您需要的相关部分。

相关内容