I would like to know how can I use nested variables in a coprocess.For example, I can use a nested variable in the following way normally.
$ a=b
$ b=lol
$ echo ${!a}
lol
But I can't do this for a coprocess, at least in shell script:
$ coproc a { while :;do echo lol;done; }
[1] 15827
$ b=a
$ read test <&${!b[0]}
$ echo $test
lol
This works, but this
#!/bin/bash
send_message() { echo "$2">$1; }
question() {
TARGET="$1"
echo "Why hello there.
Would you like some tea (y/n)?"
read answer
[[ $answer =~ ^([yY][eE][sS]|[yY])$ ]] && echo "OK then, here you go: http://www.rivertea.com/blog/wp-content/uploads/2013/12/Green-Tea.jpg" || echo "OK then."
until [ "$SUCCESS" = "y" ] ;do
send_keyboard "$TARGET" "Do you like Music?" "Yass!" "No"
read answer
case $answer in
'Yass!') echo "Goody!";SUCCESS=y;;
'No') echo "Well that's weird";SUCCESS=y;;
*) SUCCESS=n;;
esac
done
}
startproc() {
local copname="$1"
local TARGET="$2"
coproc $copname { question "$TARGET" 2>&1; }
outproc "$copname" "$TARGET"
}
inproc() {
local coproc="$1"
shift
echo "$@" >&"${!coproc[1]}"
}
outproc() {
local coproc="$1"
local TARGET="$2"
while read -t 1 -u "${!coproc[0]}" line; do send_message "$TARGET" "$line"; done
}
startproc a test
inproc a y
Does not:
~ $ bash -vx t.sh
#!/bin/bash
send_message() { echo "$2">$1; }
question() {
TARGET="$1"
echo "Why hello there.
Would you like some tea (y/n)?"
read answer
[[ $answer =~ ^([yY][eE][sS]|[yY])$ ]] && echo "OK then, here you go: http://www.rivertea.com/blog/wp-content/uploads/2013/12/Green-Tea.jpg" || echo "OK then."
until [ "$SUCCESS" = "y" ] ;do
send_keyboard "$TARGET" "Do you like Music?" "Yass!" "No"
read answer
case $answer in
'Yass!') echo "Goody!";SUCCESS=y;;
'No') echo "Well that's weird";SUCCESS=y;;
*) SUCCESS=n;;
esac
done
}
startproc() {
local copname="$1"
local TARGET="$2"
coproc $copname { question "$TARGET" 2>&1; }
outproc "$copname" "$TARGET"
}
inproc() {
local coproc="$1"
shift
echo "$@" >&"${!coproc[1]}"
}
outproc() {
local coproc="$1"
local TARGET="$2"
while read -t 1 -u "${!coproc[0]}" line; do send_message "$TARGET" "$line"; done
}
startproc a test
+ startproc a test
+ local copname=a
+ local TARGET=test
+ outproc a test
+ local coproc=a
+ local TARGET=test
+ read -t 1 -u '' line
t.sh: line 34: read: : invalid file descriptor specificationinproc a y
+ inproc a y
+ local coproc=a
+ shift
+ echo y
t.sh: line 28: "${!coproc[1]}": Bad file descriptor
~ $ + question test
~ $
Thanks in advance.
I can't find any documentation which would support the behaviour, so I'm inclined to think it is a bug.
The coproc
command does not expand $name
in
coproc $name COMMAND
Consequently, it ends up creating a coprocess array called, literally, $name
. That's not a legal array name, but since coproc
is working at a relatively low level, it succeeds in creating the array.
Eg:
$ echo $BASH_VERSION
4.3.11(1)-release
$ coproc $name { echo hello; }
[1] 23424
$ declare -p '$name'
declare -a $name='([0]="63" [1]="60")'
[1]+ Done coproc $name { echo hello; }
So the indirect reference doesn't work because the coproc array is not called what you think it is.
I suppose you could work around by using eval, but you'd need to get the quoting right on the command to be coproc'd. I'd suggest defining a function to make it easier.
By the way, in ${!coproc[1]}
, the subscript [1]
is applied before the !
, so it means "the variable whose name is ${coproc[1]}
, rather than "element 1 of the array whose name is $coproc
. That works with 0 because ${x}
and ${x[0]}
mean exactly the same thing, regardless of whether x
is a scalar or a (non-associative) array, but that is really a misleading coincidence. You need to include the subscript in the variable through which you are indirecting:
cp1=$coproc[1] # *Not* an array lookup, just a simple substitution
cmd >&${!cp1}