Вложенная переменная сопроцесса в bash
Я хотел бы знать, как я могу использовать вложенные переменные в сопроцессе. Например, я могу использовать вложенную переменную следующим образом, как обычно.
$ a=b
$ b=lol
$ echo ${!a}
lol
Но я не могу сделать это для сопроцесса, по крайней мере, в сценарии оболочки:
$ coproc a { while :;do echo lol;done; }
[1] 15827
$ b=a
$ read test <&${!b[0]}
$ echo $test
lol
Это работает, но это
#!/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
Не:
~ $ 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
~ $
Заранее спасибо.
1 ответ
Я не могу найти документацию, которая бы поддерживала поведение, поэтому я склонен думать, что это ошибка.
coproc
команда не расширяется $name
в
coproc $name COMMAND
Следовательно, он в конечном итоге создает массив сопроцессов, который называется буквально $name
, Это не допустимое имя массива, но так как coproc
работает на относительно низком уровне, ему удается создать массив.
Например:
$ 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; }
Таким образом, косвенная ссылка не работает, потому что массив coproc не называется тем, что вы думаете.
Я полагаю, вы могли бы обойтись с помощью eval, но вам нужно было бы правильно указать цитату в команде, которая будет скопирована. Я бы предложил определить функцию, чтобы сделать ее проще.
Кстати, в ${!coproc[1]}
нижний индекс [1]
применяется до !
, так что это означает "переменная, имя которой ${coproc[1]}
, а не "элемент 1 массива, имя которого $coproc
, Это работает с 0, потому что ${x}
а также ${x[0]}
означает одно и то же, независимо от того, x
является скалярным или (неассоциативным) массивом, но это действительно вводящее в заблуждение совпадение. Вам необходимо включить индекс в переменную, через которую вы выполняете косвенную передачу:
cp1=$coproc[1] # *Not* an array lookup, just a simple substitution
cmd >&${!cp1}