![通过 sed 过滤 stderr 时 Bash 脚本挂起](https://linux22.com/image/203257/%E9%80%9A%E8%BF%87%20sed%20%E8%BF%87%E6%BB%A4%20stderr%20%E6%97%B6%20Bash%20%E8%84%9A%E6%9C%AC%E6%8C%82%E8%B5%B7.png)
介绍
我有一个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 环境?~/.bashrc
AskUbuntu 上似乎引用了您需要的相关部分。