840 lines
20 KiB
YAML
840 lines
20 KiB
YAML
name: "Compound commands: coproc"
|
|
|
|
# NOTE: Coproc tests must defend against TWO race conditions caused by bash's
|
|
# SIGCHLD handler:
|
|
#
|
|
# 1. The handler clears the COPROC array when the coproc child exits, so
|
|
# ${COPROC[0]} can become empty before the parent captures it.
|
|
# 2. The handler ALSO closes the underlying pipe FDs, so even after capturing
|
|
# the integer FD, reading from it returns EOF immediately.
|
|
#
|
|
# We defend against both by:
|
|
# (a) Having the coproc body block on `read -r _ < _sync` first, so it can't
|
|
# exit before the parent dups the FD (no SIGCHLD can fire yet).
|
|
# (b) Using `exec 9<&${COPROC[0]}` to dup the pipe to a fresh FD that bash
|
|
# does NOT manage as part of the coproc, so it survives SIGCHLD cleanup.
|
|
# (c) Then `echo x > _sync` releases the coproc to do its real work.
|
|
#
|
|
# We use explicit FD 9 (rather than `{fd}<&...` auto-assignment) for portability.
|
|
|
|
cases:
|
|
#
|
|
# Basic invocation
|
|
#
|
|
- name: "Unnamed coproc with brace group"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "hello from coproc"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Unnamed coproc with subshell"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc ( read -r _ < _sync; echo "hello from subshell coproc" )
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Named coproc with brace group"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc MYCOPROC { read -r _ < _sync; echo "named coproc"; }
|
|
exec 9<&${MYCOPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Named coproc with subshell"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc MYSUB ( read -r _ < _sync; echo "named subshell coproc" )
|
|
exec 9<&${MYSUB[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with simple command"
|
|
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc cat
|
|
rfd=${COPROC[0]}
|
|
wfd=${COPROC[1]}
|
|
echo "input line" >&$wfd
|
|
exec {wfd}>&-
|
|
read -r line <&$rfd
|
|
echo "got: $line"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with multi-statement brace group"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "line1"
|
|
echo "line2"
|
|
echo "line3"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# COPROC and COPROC_PID variable validation via functional use
|
|
#
|
|
- name: "COPROC array read FD is functional"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "via read fd"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
read -r line <&9
|
|
echo "got: $line"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Named coproc FDs are functional"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc MYPROC { read -r _ < _sync; echo "named fd test"; }
|
|
exec 9<&${MYPROC[0]}
|
|
echo x > _sync
|
|
read -r line <&9
|
|
echo "got: $line"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Reading from coproc stdout
|
|
#
|
|
- name: "Read coproc output with cat"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "output from coproc"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Read coproc output with read builtin"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "readline test"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
read -r line <&9
|
|
echo "got: $line"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Read multiple lines from coproc"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "first"
|
|
echo "second"
|
|
echo "third"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Read multiple lines with read builtin"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "line1"
|
|
echo "line2"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
{
|
|
read -r first
|
|
read -r second
|
|
} <&9
|
|
echo "first=$first"
|
|
echo "second=$second"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Named coproc read"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc READER { read -r _ < _sync; echo "from named"; }
|
|
exec 9<&${READER[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Writing to coproc stdin
|
|
#
|
|
- name: "Write to coproc stdin and read back"
|
|
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc cat
|
|
rfd=${COPROC[0]}
|
|
wfd=${COPROC[1]}
|
|
echo "hello coproc" >&$wfd
|
|
exec {wfd}>&-
|
|
read -r line <&$rfd
|
|
echo "got: $line"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Bidirectional communication"
|
|
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc {
|
|
while read -r line; do
|
|
echo "processed: $line"
|
|
done
|
|
}
|
|
rfd=${COPROC[0]}
|
|
wfd=${COPROC[1]}
|
|
echo "msg1" >&$wfd
|
|
echo "msg2" >&$wfd
|
|
exec {wfd}>&-
|
|
{
|
|
read -r out1
|
|
read -r out2
|
|
} <&$rfd
|
|
echo "$out1"
|
|
echo "$out2"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Named coproc bidirectional"
|
|
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc BIDIR {
|
|
while read -r line; do
|
|
echo "echo: $line"
|
|
done
|
|
}
|
|
rfd=${BIDIR[0]}
|
|
wfd=${BIDIR[1]}
|
|
echo "test1" >&$wfd
|
|
echo "test2" >&$wfd
|
|
exec {wfd}>&-
|
|
{
|
|
read -r out1
|
|
read -r out2
|
|
} <&$rfd
|
|
echo "$out1"
|
|
echo "$out2"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Close write FD to signal EOF"
|
|
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc {
|
|
count=0
|
|
while read -r line; do
|
|
count=$((count + 1))
|
|
done
|
|
echo "read $count lines"
|
|
}
|
|
rfd=${COPROC[0]}
|
|
wfd=${COPROC[1]}
|
|
echo "a" >&$wfd
|
|
echo "b" >&$wfd
|
|
echo "c" >&$wfd
|
|
exec {wfd}>&-
|
|
read -r result <&$rfd
|
|
echo "$result"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Bidirectional with cat for EOF"
|
|
skip: true # TODO(coproc): hangs - stdout pipe not fully closed after coproc exits
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc {
|
|
while read -r line; do
|
|
echo "processed: $line"
|
|
done
|
|
}
|
|
rfd=${COPROC[0]}
|
|
wfd=${COPROC[1]}
|
|
echo "msg1" >&$wfd
|
|
echo "msg2" >&$wfd
|
|
exec {wfd}>&-
|
|
cat <&$rfd
|
|
wait
|
|
echo "DONE"
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Coproc with compound command bodies
|
|
#
|
|
- name: "Coproc running a for loop"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
for i in 1 2 3; do
|
|
echo "iteration $i"
|
|
done
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc running a while loop"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
n=1
|
|
while [ $n -le 3 ]; do
|
|
echo "count $n"
|
|
n=$((n + 1))
|
|
done
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with conditionals"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
if true; then
|
|
echo "true branch"
|
|
else
|
|
echo "false branch"
|
|
fi
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with case statement"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
val="hello"
|
|
case $val in
|
|
hello) echo "matched hello";;
|
|
*) echo "no match";;
|
|
esac
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc body with pipeline"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo -e "banana\napple\ncherry" | sort
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc body with command substitution"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
result=$(echo "hello" | tr a-z A-Z)
|
|
echo "$result"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with arithmetic operations"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
a=5
|
|
b=3
|
|
echo $((a + b))
|
|
echo $((a * b))
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Exit status and lifecycle
|
|
#
|
|
- name: "Coproc statement returns 0"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo done; }
|
|
status=$?
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
echo "exit status: $status"
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with failing body returns 0 immediately"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc { exit 42; }
|
|
echo "coproc start status: $?"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Wait with no args waits for coproc"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "coproc done"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
echo "after wait"
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Error cases
|
|
#
|
|
- name: "Invalid coproc name"
|
|
ignore_stderr: true
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc 123bad { echo x; }
|
|
echo "exit: $?"
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Coproc in different contexts
|
|
#
|
|
- name: "Coproc inside a function"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
start_coproc() {
|
|
coproc { read -r _ < _sync; echo "from function coproc"; }
|
|
}
|
|
start_coproc
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc inside a conditional"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
if true; then
|
|
coproc { read -r _ < _sync; echo "conditional coproc"; }
|
|
fi
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc inside a loop body"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
for i in 1; do
|
|
coproc { read -r _ < _sync; echo "loop coproc $i"; }
|
|
done
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Named coproc inside a function"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
f() {
|
|
coproc FUNCPROC { read -r _ < _sync; echo "named in func"; }
|
|
}
|
|
f
|
|
exec 9<&${FUNCPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Multiple coprocs and variable lifecycle
|
|
#
|
|
- name: "Second unnamed coproc replaces first"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "first"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
exec 9<&-
|
|
wait
|
|
coproc { read -r _ < _sync; echo "second"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Sequential named coprocs with different names"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc PROC1 { read -r _ < _sync; echo "proc1"; }
|
|
exec 9<&${PROC1[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
exec 9<&-
|
|
wait
|
|
coproc PROC2 { read -r _ < _sync; echo "proc2"; }
|
|
exec 9<&${PROC2[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Environment and variable scope
|
|
#
|
|
- name: "Coproc inherits parent environment"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
export MY_VAR="inherited"
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "MY_VAR=$MY_VAR"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc inherits non-exported variables"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
LOCAL_VAR="visible"
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; echo "LOCAL_VAR=$LOCAL_VAR"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc cannot modify parent variables"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
PARENT_VAR="original"
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; PARENT_VAR="modified"; echo "in coproc: $PARENT_VAR"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
echo "in parent: $PARENT_VAR"
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc inherits functions"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
greet() { echo "hello $1"; }
|
|
export -f greet
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; greet "world"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc inherits aliases"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
shopt -s expand_aliases
|
|
alias myecho='echo ALIASED:'
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; myecho "test"; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Coproc with redirections in body
|
|
#
|
|
- name: "Coproc body with stderr redirection"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "stdout msg"
|
|
echo "stderr msg" >&2
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc body writing to a file"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "file content" > /tmp/coproc_test_$$
|
|
echo "wrote file"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
cat /tmp/coproc_test_$$
|
|
rm -f /tmp/coproc_test_$$
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Coproc with various data patterns
|
|
#
|
|
- name: "Coproc producing empty output"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc { read -r _ < _sync; true; }
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
echo "after empty coproc"
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc producing multiple lines of output"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
|
echo "line $i"
|
|
done
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
count=0
|
|
while read -r line; do
|
|
count=$((count + 1))
|
|
done <&9
|
|
echo "read $count lines"
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with multiline string output"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
cat <<'HEREDOC'
|
|
first line
|
|
second line
|
|
third line
|
|
HEREDOC
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
cat <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Coproc output transformation
|
|
#
|
|
- name: "Transform coproc output to uppercase"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "hello"
|
|
echo "world"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
while read -r line; do
|
|
echo "$line" | tr a-z A-Z
|
|
done <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc output filtered with case"
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
mkfifo _sync
|
|
coproc {
|
|
read -r _ < _sync
|
|
echo "apple"
|
|
echo "banana"
|
|
echo "avocado"
|
|
echo "cherry"
|
|
}
|
|
exec 9<&${COPROC[0]}
|
|
echo x > _sync
|
|
while read -r line; do
|
|
case $line in
|
|
a*) echo "starts with a: $line";;
|
|
esac
|
|
done <&9
|
|
wait
|
|
args: ["./test.sh"]
|
|
|
|
#
|
|
# Tests requiring wait with job specs (known failures)
|
|
#
|
|
- name: "Wait for specific coproc PID"
|
|
known_failure: true # TODO(wait): wait with job specs not implemented
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc { echo "done"; }
|
|
fd=${COPROC[0]}
|
|
cat <&$fd
|
|
wait $COPROC_PID
|
|
echo "wait status: $?"
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Coproc with failing body - wait captures exit status"
|
|
known_failure: true # TODO(wait): wait with job specs not implemented
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc { exit 42; }
|
|
wait $COPROC_PID
|
|
echo "exit status: $?"
|
|
args: ["./test.sh"]
|
|
|
|
- name: "Wait for named coproc PID"
|
|
known_failure: true # TODO(wait): wait with job specs not implemented
|
|
test_files:
|
|
- path: "test.sh"
|
|
contents: |
|
|
coproc MYPROC { echo "done"; }
|
|
fd=${MYPROC[0]}
|
|
cat <&$fd
|
|
wait $MYPROC_PID
|
|
echo "status: $?"
|
|
args: ["./test.sh"]
|