Использование / PREC / $ PPID / FD / 0
является ненадежной: родитель селектора
может не иметь терминала в качестве его ввода.
Существует стандартный путь , который всегда относится к терминалу текущего процесса: / dev / tty
.
nl "$INPUT" >/dev/tty
read -p"Select options: " </dev/tty
или
exec </dev/tty >/dev/tty
nl "$INPUT"
read -p"Select options: "
Я написал небольшую функцию: она не будет отвечать о том, что вы просили цепочки труб, но решит вашу проблему.
inf() ( [ -n "$ZSH_VERSION" ] && emulate sh
unset n i c; set -f; tab=' ' IFS='
'; _in() until [ "$((i+=1))" -gt 5 ] && exit 1
printf '\nSelect: '
read -r c && [ -n "${c##*[!- 0-9]*}" ]
do echo "Invalid selection."
done
_out() for n do i=; [ "$n" = . ] &&
printf '"${%d#*$tab}" ' $c ||
until c="${c#*.} ${i:=${n%%-*}}"
[ "$((i+=1))" -gt "${n#*-}" ]
do :; done; done
set -- $(grep "$@"|nl -w1 -s "$tab"|tee /dev/tty)
i=$((($#<1)*5)); _in </dev/tty >/dev/tty
eval "printf '%s\n' $(c=$c\ . IFS=\ ;_out $c)"
)
Функция передает все аргументы, которые вы сразу же передаете в grep
. Если вы используете shell-глобус для указания файлов, которые он должен прочитать, то он вернёт все совпадения во всех файлах, начиная с первого в порядке глобуса и заканчивая последним.
grep
передает свой вывод в nl
, который нумерует каждую строку и передает свой вывод в tee
, который дублирует свой вывод как в stdout
, так и в /dev/tty
. Это означает, что вывод с конвейера одновременно выводится как на массив аргументов функции, где он разбивается на \n
ewlines, так и на терминал по мере его работы.
Далее функция _in()
пытается прочитать
в выборке, если от предыдущего действия получен как минимум 1 результат максимум пять раз. Выбор может состоять только из чисел, разделенных пробелами, или же диапазонов чисел, разделенных -
. Если что-нибудь еще является -
(включая пустую строку), то он попробует еще раз - но только, как и прежде, максимум пять раз.
Последняя функция _out()
анализирует выбор пользователя и расширяет в нем любые диапазоны. Она распечатывает свои результаты в виде "${[num]}"
для каждого - таким образом, совпадает значение строк, хранящихся в массиве аргументов inf()
. Этот вывод представляет собой eval
ed в виде аргумента к printf
, который, таким образом, печатает только те строки, которые выбрал пользователь.
Он явно считывает из терминала
и печатает только меню Select:
на stderr
, что делает его достаточно дружественным к трубопроводу. Например, это работает следующим образом:
seq 100 |inf 3|grep 8
1 3
2 13
3 23
4 30
5 31
6 32
7 33
8 34
9 35
10 36
11 37
12 38
13 39
14 43
15 53
16 63
17 73
18 83
19 93
Select: 6 9 12-18
38
83
Но вы можете использовать любые опции grep
, а также любое количество имён файлов. То есть, вы можете использовать любой вид, кроме одного - в качестве побочного эффекта при разборе с помощью $IFS
, он не будет работать, если вы ищете пустые строки. Но кто захочет выбирать из пронумерованного списка пустых строк?
Последнее замечание: поскольку это работает путем прямого преобразования числового ввода пользователя в числовые параметры позиционирования, хранящиеся в массиве аргументов функции, то на выходе будет то, что пользователь выберет, столько раз, сколько пользователь выберет, и в каком бы порядке пользователь не выбрал.
For example:
seq 1000 | inf 00\$
1 100
2 200
3 300
4 400
5 500
6 600
7 700
8 800
9 900
10 1000
Select: 4-8 1 1 3-6
400
500
600
700
800
100
100
300
400
500
600