bash:如何确保与 exec 一起使用的进程替换终止?

2023-11-26

If I run

$#/bin/bash
for i in `seq 5`; do
    exec 3> >(sed -e "s/^/$i: /"; echo "$i-")
    echo foo >&3
    echo bar >&3
    exec 3>&-
done

那么结果不同步;它可能是这样的:

1: foo
1: bar
2: foo
2: bar
1-
3: foo
3: bar
2-
3-
4: foo
5: foo
4: bar
5: bar
4-
5-

如何确保进程替换>(...)在进行下一次迭代之前是否已完成?

插入sleep 0.1 after exec 3>&-有帮助,但它不优雅、效率低下,并且不能保证始终有效。

编辑:这个例子可能看起来很傻,但这只是为了说明。我正在做的是在循环中读取输入流,将每一行输入到一个在循环期间偶尔会发生变化的进程。用代码更容易解​​释:

# again, simplified for illustration
while IFS= read line; do
    case $line in
    @*)
        exec 3>&-
        filename=${line:1}
        echo "starting $filename"
        exec 3> >(sort >"$filename"; echo "finished $filename")
        ;;
    *)
        echo "$line" >&3
        ;;
    esac
done
exec 3>&-

以下工作在 bash 4 中,使用协进程:

#!/bin/bash
fd_re='^[0-9]+$'
cleanup_and_wait() {
    if [[ ${COPROC[1]} =~ $fd_re ]] ; then
        eval "exec ${COPROC[1]}<&-"
        echo "waiting for $filename to finish" >&2
        wait $COPROC_PID
    fi
}

while IFS= read -r line; do
    case $line in
    @*)
        cleanup_and_wait
        filename=${line:1}
        echo "starting $filename" >&2
        coproc { sort >"$filename"; echo "Finished with $filename" >&2; }
        ;;
    *)
        printf '%s\n' "$line" >&${COPROC[1]}
        ;;
    esac
done
cleanup_and_wait

对于 bash 的早期版本,可以使用命名管道来代替:

cleanup_and_wait() {
    if [[ $child_pid ]] ; then
      exec 4<&-
      echo "waiting for $filename to finish" >&2
      wait $child_pid
    fi
}

# this is a bit racy; without a force option to mkfifo,
# however, the race is unavoidable
fifo_name=$(mktemp -u -t fifo.XXXXXX)
if ! mkfifo "$fifo_name" ; then
  echo "Someone else may have created our temporary FIFO before we did!" >&2
  echo "This can indicate an attempt to exploit a race condition as a" >&2
  echo "security vulnarability and should always be tested for." >&2
  exit 1
fi

# ensure that we clean up even on unexpected exits
trap 'rm -f "$fifo_name"' EXIT

while IFS= read -r line; do
    case $line in
    @*)
        cleanup_and_wait
        filename=${line:1}
        echo "starting $filename" >&2
        { sort >"$filename"; echo "finished with $filename" >&2; } <"$fifo_name" &
        child_pid=$!
        exec 4>"$fifo_name"
        ;;
    *)
        printf '%s\n' "$line" >&4
        ;;
    esac
done
cleanup_and_wait

一些注意事项:

  • 使用起来更安全printf '%s\n' "$line" than echo "$line";如果一行仅包含-e,例如,某些版本echo不会用它做任何事。
  • 使用 EXIT 陷阱进行清理可确保意外的 SIGTERM 或其他错误不会留下过时的 fifo。
  • 如果您的平台提供了一种在单个原子操作中创建未知名称的 FIFO 的方法,请使用它;这将避免需要我们始终测试 mkfifo 是否成功的情况。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

bash:如何确保与 exec 一起使用的进程替换终止? 的相关文章

  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • Bash 脚本:#!/bin/bash 是什么意思? [复制]

    这个问题在这里已经有答案了 在 bash 脚本中 什么是 bin bash第一行是什么意思 UPDATE 有区别吗 bin bash and bin sh 这就是所谓的shebang http en wikipedia org wiki S
  • 如何将命令作为参数传递给 ssh [重复]

    这个问题在这里已经有答案了 我的需要是让这个命令起作用 sshpass p XXXX ssh oStrictHostKeyChecking no email protected cdn cgi l email protection sudo
  • 设置 Pyenv 的路径

    我正在尝试在我的服务器中设置 Pyenv 的加载路径 bashrc file 我正在关注这个tutorial https realpython com intro to pyenv 它要求我们在哪里设置pyenv到加载路径 然而 在我的 b
  • 将“npm run start”的输出写入文件

    我想捕获的输出npm run start在一个文件中 我遇到了大量错误 我想更好地控制如何筛选输出 当我尝试时 npm run start gt log txt 我得到一个非常简短的文件 8 行 其结尾为 34m 39m 90m wdm 3
  • 目录 * 和文件顺序

    我需要将目录中的所有文件连接到一个文件 但具有指定名称的文件必须位于输出的顶部 只是在做cat gt result将按字母顺序连接所有文件 有什么办法告诉猫放置文件vars css或任何其他输出的开头 现在我只是重命名文件需要首先000 f
  • Bash 脚本大小限制?

    我有一个 bash 脚本 在 RHEL 或 OS X 上运行时出现以下错误 第 62484 行 意外标记 换行符 附近出现语法错误 第 62484 行 o gz 这是一个自动生成的脚本 用于解决我公司使用的 Grid Engine 计算集群
  • 使用 Ansible 将二进制文件添加到 PATH

    我正在尝试安装Kiex https github com taylor kiex版本管理器Elixir http elixir lang org install html使用 Ansible 的编程语言 这些是我为此使用的戏剧 name K
  • 如何删除最后一次出现模式后的所有行?

    我想删除最后一次出现模式之后的所有行 除了模式本身 file txt honor apple redmi nokia apple samsung lg htc file txt 我想要什么 honor apple redmi nokia a
  • 使用带有curl 的内部字段分隔符

    当我做 ls IFS l 我得到了我期望的输出 当我做 curl IFShttp www google com 我不 我是否误解了内部字段分隔符 如何在不使用任何空格字符的情况下运行curl 命令 您需要将变量放在大括号内 否则 shell
  • 语法错误:for 循环变量不正确

    我正在尝试编写一个可以在后台调高收音机音量的脚本 bin sh for i 80 i lt 101 i do amixer cset numid 1 i sleep 60 done 但我有问题 alarmclock vol sh 3 ala
  • 使用 grep 查找包含所有搜索字符串的行

    我有一个文件 其中包含很多与此类似的行 id 2796 some model Profile message type MODEL SAVE fields account 14 address null modification times
  • git 别名中的 AWK 语句

    我正在尝试创建一个 git 别名来以特定格式打印日志中的所有拉取请求 但是 我在使用 AWK 删除双空格时遇到问题 这是使用以下命令的 git log 的输出 git log merges grep pull request pretty
  • grep 两个分隔符之间的子字符串

    我有很多bash使用的脚本perl内的表达式grep为了提取两个分隔符之间的子字符串 例子 echo BeginMiddleEnd grep oP lt Begin End 问题是 当我将这些脚本移植到运行的平台时busybox 融合的 g
  • 如何在数组中存储包含双引号的命令参数?

    我有一个 Bash 脚本 它生成 存储和修改数组中的值 这些值稍后用作命令的参数 对于 MCVE 我想到了任意命令bash c echo 0 0 echo 1 1 这解释了我的问题 我将用两个参数调用我的命令 option1 without
  • 如何判断 Bash 中是否存在文件?

    这会检查文件是否存在 bin bash FILE 1 if f FILE then echo File FILE exists else echo File FILE does not exist fi 我如何只检查文件是否存在not ex
  • jq:将对象数组转换为对象

    我收到了来自curl的回复 格式如下 list value 1 id 12 value 15 id 13 value 4 id 14 给定 id 之间的映射 如下所示 12 newId1 13 newId2 14 newId3 我想做这个
  • 使用 find 命令搜索直到第一个匹配项

    我只需要搜索可以在任何地方的特定目录有没有办法运行此命令直到第一个匹配 谢谢 我现在使用 find noleaf name experiment type d wc l 正如鲁道夫 米尔鲍尔 Rudolf M hlbauer 所提到的 qu
  • 如何在 Linux shell 中将十六进制转换为 ASCII 字符?

    假设我有一个字符串5a 这是 ASCII 字母的十六进制表示Z 我需要找到一个 Linux shell 命令 它将接受一个十六进制字符串并输出该十六进制字符串代表的 ASCII 字符 所以如果我这样做 echo 5a command im
  • 两种情况或 if 哪个更快? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我必须制作一个 非常 轻的脚本 它将接受用户的选项并调用脚本中的函数来执行一些任务 现在我可以使用 IF 和 CASE 选项 但我想知道两

随机推荐