Это прекрасно работает для меня, останавливается и позволяет мне ввести либо 1
, либо 2
.
См. Следующую расшифровку:
pax$ cat qq.sh
echo "Did you see a display?"
select YN in "yes" "no" ; do
case $YN in
yes)
echo YES
break
;;
no)
echo NO
break
;;
esac
done
pax$ ./qq.sh
Did you see a display?
1) yes
2) no
#? 1
YES
pax$ ./qq.sh
Did you see a display?
1) yes
2) no
#? 2
NO
pax$ _
Вы уверены, что стандартвход подключен к вашему терминалу в этот момент?
Поскольку вы подтвердили мои подозрения, что ваш стандартный вход не подключен к терминалу, является несколько сложным способомчтобы исправить это, поиграв с дескрипторами файлов.
Рассмотрим следующий код, который выполняет то, что вы указали в своем комментарии (вызывая функцию, принимающую стандартный ввод из цикла, который перенаправил стандартный ввод):
fn() {
echo "Did you see a display?"
select YN in "yes" "no" ; do
case $YN in
yes)
echo YES $YN $REPLY
break
;;
no)
echo NO $YN $REPLY
break
;;
esac
done
}
echo 'A
B
C
D' | while read ; do
echo $REPLY
fn
echo ====
done
Если вы запустите этот код, вы увидите:
A
Did you see a display?
1) yes
2) no
#? #? #? #?
=====
Это указывает на то, что ввод был перемешан между двумя считывателями, while read
и select
.
Хитрость в решении этой проблемы состоит в том, чтобы разъединить двух читателей, изменив код следующим образом:
(echo 'A
B
C
D' | while read ; do
echo $REPLY
fn <&4
done) 4<&0
Вывод для этого:
A
Did you see a display?
1) yes
2) no
#? 1 <- my input.
YES yes 1
=====
B
Did you see a display?
1) yes
2) no
#? 2 <- my input.
NO no 2
=====
C
Did you see a display?
1) yes
2) no
#? 1 <- my input.
YES yes 1
=====
D
Did you see a display?
1) yes
2) no
#? 2 <- my input.
NO no 2
=====
Что это делает (в своем отвратительноммода) это начало недоработкичтобы у вас все получилось, с хитростью в том, что подоболочка сначала соединяет стандартный текущий вход (терминал, вероятно) с файловым дескриптором 4 для дальнейшего использования.
Внутри subshell, вы запускаете свой обычный цикл while read
, который меняет стандартный ввод (обработчик файла 0) для чтения из оператора echo
.
Но вот хитрость: когда вы вызываете свою функцию, вы говоритеон берет свой стандартный ввод из дескриптора файла 4, а не из текущего дескриптора файла 0. Так как он связан с сохраненным, оригинальным, стандартным вводом, он ничего не получит от стандартного ввода while read
(вывод echo
).
Это может занять некоторое время, чтобы обернуть вашу голову (и я вспоминаю, как мне пришлось отрывать мозги от пола, когда я впервые это увидел, так как моя голова взорвалась).Но, как только вы поймете, как это работает, вы увидите его элегантность: -)
Вывод для этого:
A
Did you see a display?
1) yes
2) no
#? 1
YES yes 1
=====
B
Did you see a display?
1) yes
2) no
#? 2
NO no 2
=====
C
Did you see a display?
1) yes
2) no
#? 1
YES yes 1
=====
D
Did you see a display?
1) yes
2) no
#? 2
NO no 2
=====
И, основываясь на вашем коде, вероятно,Хорошей отправной точкой является окружение всего лота для сохранения стандартного ввода, например:
(FILE=res.log
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
exec 3<&0
exec 0<$FILE
while read -r LINE
do
fnUseResolution $LINE app1 <&4
fnUseResolution $LINE app2 <&4
fnUseResolution $LINE app3 <&4
done
exec 0<&3
IFS=$BAKIFS) 4<&0
Я предполагаю, что ваша функция равна fnUseResolution
.
Однако, глядяв этом коде может быть проще использовать другой дескриптор файла для read
, а не select
, поскольку у вас больше контроля над этим, чем я думал.
Попробуйте:
FILE=res.log
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
#exec 3<&0
exec 4<$FILE
while read -u 4 -r LINE
do
fnUseResolution $LINE app1
fnUseResolution $LINE app2
fnUseResolution $LINE app3
done
#exec 0<&3
IFS=$BAKIFS
Опция -u 4
для чтения говорит о том, что используется файловый дескриптор 4, а не 0, и я изменил exec
, чтобы соответствовать этому.Я не тестировал его, но он должен работать нормально.
Делая это таким образом, вы никогда не меняете стандартный ввод, поэтому он должен быть в пределах функции.Кроме того, в этом случае нет причин сохранять / восстанавливать его в дескрипторе файла 3, поэтому я прокомментировал эти exec
вызовы.