标签: coprocesses

100
推荐指数
2
解决办法
3万
查看次数

使用前台终端访问在后台运行命令

我正在尝试创建一个可以运行任意命令的函数,与子进程交互(省略细节),然后等待它退出。如果成功,打字run <command>看起来就像一个裸的<command>.

如果我不与子进程交互,我会简单地写:

run() {
    "$@"
}
Run Code Online (Sandbox Code Playgroud)

但是因为我需要在它运行时与之交互,所以我使用coproc和 进行了更复杂的设置wait

run() {
    exec {in}<&0 {out}>&1 {err}>&2
    { coproc "$@" 0<&$in 1>&$out 2>&$err; } 2>/dev/null
    exec {in}<&- {out}>&- {err}>&-

    # while child running:
    #     status/signal/exchange data with child process

    wait
}
Run Code Online (Sandbox Code Playgroud)

(这是一个简化。虽然coproc重定向和所有重定向在这里并没有真正做任何不能做的有用的"$@" &事情,但我在我的实际程序中需要它们。)

"$@"命令可以是任何东西。我拥有的功能可以使用run ls等等run make,但是当我这样做时它失败了run vim。我认为它失败了,因为 Vim 检测到它是一个后台进程并且没有终端访问权限,所以它不会弹出一个编辑窗口,而是自己挂起。我想修复它,以便 Vim 正常运行。

如何coproc "$@"在“前台”中运行而父 shell 成为“后台”?“与孩子交互”部分既不读取也不写入终端,所以我不需要它在前台运行。我很高兴将 tty 的控制权交给协进程。

对于我正在做的事情来说,重要的run() …

shell job-control tty background-process coprocesses

7
推荐指数
2
解决办法
3444
查看次数

连接管道

考虑这样的例程:

alpha() { echo a b c |tr ' ' '\n'; }
Run Code Online (Sandbox Code Playgroud)

它输出一个流,我想获取输出流,对其进行转换,并将paste其与原始输出流一起使用。

如果我使用 upcasing 作为示例转换,我可以通过以下方式实现我想要的:

$ mkfifo p1 p2
$ alpha | tee p1 >( tr a-z A-Z > p2) >/dev/null &
$ paste p1 p2
a       A
b       B
c       C
Run Code Online (Sandbox Code Playgroud)

我的问题是,有没有更好的方法来做到这一点,最好是不涉及命名管道的方法?

pipe shell-script fifo coprocesses

5
推荐指数
1
解决办法
155
查看次数

coproc &lt;命令&gt; 与 &lt;命令&gt; &amp; 相同吗?

我读过的内容$coproc < command >不同于$< command > &与在子 shell 进程中coproc执行的command

但当我测试它时,它的工作原理就像$< command > &. 测试如下:

第一:测试行为$< command > &

  1. 跑步$nano &在tty1
  2. 在另一个 tty 上,输出来自$ps -t tty1 --forest表明 nano 进程是 -bash 进程的子进程(登录 bash shell 进程 -> 未创建子 shell 进程)

第二:测试行为$coproc < command >

  1. 跑步$coproc nano在tty1
  2. 在另一个 tty 上,输出来自$ps -t tty1 --forest上面相同(没有创建子 shell 进程)

也是如此$coproc < command >和一样吗$< …

bash coprocesses

5
推荐指数
1
解决办法
2305
查看次数

命令替换下的 coproc 和命名管道行为

我需要在 zsh shell 脚本中创建一个函数,由命令替换调用,将状态与对相同命令替换的后续调用进行通信。

类似于 C 在函数中的静态变量(非常粗略地说)。

为此,我尝试了两种方法 - 一种使用协处理器,一种使用命名管道。命名管道方法,我无法开始工作 - 这令人沮丧,因为我认为它会解决我在协处理器上遇到的唯一问题 - 也就是说,如果我从终端进入一个新的 zsh shell,我似乎没有能够看到父 zsh 会话的 coproc。

我已经创建了简化的脚本来说明下面的问题 - 如果您对我正在尝试做的事情感到好奇 - 它正在向子弹列车 zsh 主题添加一个新的有状态组件,该组件将由命令替换 build_prompt( ) 函数在这里:https : //github.com/caiogondim/bullet-train.zsh/blob/d60f62c34b3d9253292eb8be81fb46fa65d8f048/bullet-train.zsh-theme#L692

脚本 1 - 协处理器

#!/usr/bin/env zsh

coproc cat
disown
print 'Hello World!' >&p

call_me_from_cmd_subst() {
    read get_contents <&p
    print "Retrieved: $get_contents"
    print 'Hello Response!' >&p
    print 'Response Sent!'
}

# Run this first
call_me_from_cmd_subst

# Then comment out the above call
# And run this instead
#print "$(call_me_from_cmd_subst)" …
Run Code Online (Sandbox Code Playgroud)

zsh pipe shell-script fifo coprocesses

5
推荐指数
1
解决办法
220
查看次数

是否可以有多个并发协进程?

下面的测试脚本1目的是启动一个“外部”协进程(运行),在一个-loop 中从这个协进程中读取,并且对于读取的每一行,打印一行标识外部循环的当前迭代,启动一个“内部”协进程(也正在运行,带有新参数),在嵌套的 while 循环中从这个内部协进程读取,然后清理这个内部协进程。嵌套的 while 循环为它从内部协进程读取的每一行打印一些输出。seq 3whileseq

#!/bin/bash
# filename: coproctest.sh
PATH=/bin:/usr/bin

coproc OUTER { seq 3; }
SAVED_OUTER_PID="${OUTER_PID}"

exec {OUTER_READER}<&"${OUTER[0]}"
while IFS= read -r -u "${OUTER_READER}" OUTER_INDEX; do

    printf -- '%d\n' "${OUTER_INDEX}"

    START=$(( OUTER_INDEX * 1000000 ))
    FINISH=$(( START + OUTER_INDEX ))

    # (
      coproc INNER { seq "${START}" "${FINISH}"; }
      SAVED_INNER_PID="${INNER_PID}"
      exec {INNER_READER}<&"{INNER[0]}"

      while IFS= read -r -u "${INNER_READER}" INNER_INDEX; do
          printf -- '    %d\n' "${INNER_INDEX}"
      done

      exec {INNER_READER}<&-

      wait "${SAVED_INNER_PID}" …
Run Code Online (Sandbox Code Playgroud)

scripting bash shell-script coprocesses

4
推荐指数
1
解决办法
760
查看次数