ОБНОВЛЯТЬ- похоже, это что-то странное с bash 4.3.42, так как он отлично работает с 4.3.46. Оставляю этот пост для тех, кто столкнется с той же проблемой в будущем.
Когда я запускаю эту команду в командной строке bash, она работает правильно:
% (TMOUT=3; s="no selection"; select s in a b c ; do break ; done; echo $s)
1) a
2) b
3) c
#?
no selection
% _
Результат: отображаетнет выбораи возвращается в командную строку.
Однако когда я помещаю его в скрипт и запускаю его, он постоянно запрашивает выбор.
% cat a.sh
#!/bin/bash
(TMOUT=3; s="no selection"; select s in a b c ; do break ; done; echo $s)
% ./a.sh
Результат:
1) a
2) b
3) c
#? 1) a
2) b
3) c
#? 1) a
2) b
3) c
#? ^C
% _
Почему так? Мой главный вопрос -как заставить это работать в скрипте?!
ОБНОВЛЕНО
% bash --version
GNU bash, version 4.3.42(1)-release (x86_64-unknown-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
% uname
Linux lx1 2.6.32-642.6.2.el6.x86_64 #1 SMP Mon Oct 24 10:22:33 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux
решение1
Из руководства:
TMOUT Если установлено значение больше нуля, TMOUT рассматривается как тайм-аут по умолчанию для встроенной функции read. Команда select завершается, если ввод не поступает в течение TMOUT секунд, когда ввод поступает с терминала. В интерактивной оболочке значение интерпретируется как количество секунд ожидания ввода после выдачи первичного приглашения. Bash завершается после ожидания в течение этого количества секунд, если ввод не поступает.
Итак, первый случай связан с интерактивной оболочкой.
$ ps -aef|grep bash; echo "before"; (TMOUT=3; s="no selection"; ps -aef|grep bash; select s in a b c ; do break ; done; echo $s;ps -aef|grep bash);echo "after";ps -aef|grep bash
asktyagi 4926 23767 0 09:40 pts/0 00:00:00 grep --color=auto bash
asktyagi 23767 23741 0 09:03 pts/0 00:00:00 -bash
**before**
asktyagi 4927 23767 0 09:40 pts/0 00:00:00 -bash
asktyagi 4929 4927 0 09:40 pts/0 00:00:00 grep --color=auto bash
asktyagi 23767 23741 0 09:03 pts/0 00:00:00 -bash
1) a
2) b
3) c
#?
no selection
asktyagi 4927 23767 0 09:40 pts/0 00:00:00 -bash
asktyagi 4931 4927 0 09:40 pts/0 00:00:00 grep --color=auto bash
asktyagi 23767 23741 0 09:03 pts/0 00:00:00 -bash
**after**
asktyagi 4933 23767 0 09:40 pts/0 00:00:00 grep --color=auto bash
asktyagi 23767 23741 0 09:03 pts/0 00:00:00 -bash
Теперь со сценарием
$ cat a.sh
#!/bin/bash
(TMOUT=3; s="no selection"; select s in a b c ; do break ; done; echo $s)
ps -aef|grep bash
$ sh a.sh
1) a
2) b
3) c
#?
no selection
asktyagi 5201 5188 0 09:41 pts/0 00:00:00 grep bash
asktyagi 23767 23741 0 09:03 pts/0 00:00:00 -bash
решение2
Используйте timeout
команду. Этот пример можно улучшить, но он передает суть. Сначала используйте trap
команду bash-builtin, чтобы запустить что-то при выходе, затем запустите свой цикл. Он работает следующим образом:
#] timeout 3s sh -c 'trap "echo no selection" EXIT; select s in a b c ; do break ; done; '
1) a
2) b
3) c
#? <waits 3 seconds>no selection
решение3
Итак, в конечном итоге я написал свой собственный выбор, который можно использовать в сценарии.
# $1 timeout
# rest - selection
function select_ {
t=$1
shift
arr=($*)
i=1
for a in $*; do
echo "$i) $a" >$(tty)
((i++))
done
echo "TIMEOUT: In ${t} seconds ${arr[0]} will be automatically selected." >$(tty)
printf "#? " >$(tty)
read -t $t x
[ "$x" == "" ] && {
x=1
echo "$x" >$(tty)
}
((x=x+0))
[ "$x" -ge 1 -a "$x" -le ${#arr[@]} ] && {
((x--))
echo ${arr[$x]}
}
}
Как это использовать:
select_ 10 a b c
Пример:
$ ./x.sh
1) a
2) b
3) c
TIMEOUT: In 10 seconds a will be automatically selected.
#? 2
b
$ ./x.sh
1) a
2) b
3) c
TIMEOUT: In 10 seconds a will be automatically selected.
#? 1
a