2016-01-03 2 views
1

Я хотел бы знать, как использовать вложенные переменные в сопроцессе. Например, я могу использовать вложенную переменную следующим образом.Вложенная переменная coprocess в bash

$ a=b 
$ b=lol 
$ echo ${!a} 
lol 

Но я не могу сделать это для coprocess, по крайней мере, в сценарии оболочки:

$ 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 "[email protected]" >&"${!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 "[email protected]" >&"${!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 

Следовательно, он заканчивает тем, что создание массива coprocess под названием, в буквальном смысле, $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'd. Я бы предложил определить функцию, чтобы сделать ее проще.


Кстати, в ${!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} 
+0

Спасибо! Это действительно помогло мне. Теперь все, что мне нужно сделать, это использовать некоторые DHH (опасные и ужасные хаки, такие как eval;) – Danogentili

+0

@ Danogentili: Да, я просто добавил предложение об этом, так как я не вижу никаких других очевидных обходов – rici

+0

Я также заметил другое странное поведение: я не могу перенаправить вывод программы на вложенный файловый дескриптор (но я могу его прочитать) – Danogentili