有人可以提供几个关于如何使用的例子coproc
吗?
我正在尝试创建一个可以运行任意命令的函数,与子进程交互(省略细节),然后等待它退出。如果成功,打字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() …
考虑这样的例程:
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)
我的问题是,有没有更好的方法来做到这一点,最好是不涉及命名管道的方法?
我读过的内容$coproc < command >
不同于$< command > &
与在子 shell 进程中coproc
执行的command
但当我测试它时,它的工作原理就像$< command > &
. 测试如下:
第一:测试行为$< command > &
。
$nano &
在tty1上$ps -t tty1 --forest
表明 nano 进程是 -bash 进程的子进程(登录 bash shell 进程 -> 未创建子 shell 进程)第二:测试行为$coproc < command >
$coproc nano
在tty1上$ps -t tty1 --forest
上面相同(没有创建子 shell 进程)也是如此$coproc < command >
和一样吗$< …
我需要在 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) 下面的测试脚本1的目的是启动一个“外部”协进程(运行),在一个-loop 中从这个协进程中读取,并且对于读取的每一行,打印一行标识外部循环的当前迭代,启动一个“内部”协进程(也正在运行,带有新参数),在嵌套的 while 循环中从这个内部协进程读取,然后清理这个内部协进程。嵌套的 while 循环为它从内部协进程读取的每一行打印一些输出。seq 3
while
seq
#!/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) coprocesses ×6
bash ×3
shell-script ×3
fifo ×2
pipe ×2
shell ×2
zsh ×2
job-control ×1
ksh ×1
scripting ×1
tty ×1