Как считать ввод данных пользователем при использовании сценария в канале

Подобный ttyconv существует также tconv, записанный в C Rich Felker.

См.: Ре: призыв к фиксации aterm/rxvt/etc...

9
08.11.2014, 23:01
2 ответа

Использование / 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: "
7
27.01.2020, 20:07

Я написал небольшую функцию: она не будет отвечать о том, что вы просили цепочки труб, но решит вашу проблему.

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 . Это означает, что вывод с конвейера одновременно выводится как на массив аргументов функции, где он разбивается на \newlines, так и на терминал по мере его работы.

Далее функция _in() пытается прочитать в выборке, если от предыдущего действия получен как минимум 1 результат максимум пять раз. Выбор может состоять только из чисел, разделенных пробелами, или же диапазонов чисел, разделенных -. Если что-нибудь еще является - (включая пустую строку), то он попробует еще раз - но только, как и прежде, максимум пять раз.

Последняя функция _out() анализирует выбор пользователя и расширяет в нем любые диапазоны. Она распечатывает свои результаты в виде "${[num]}" для каждого - таким образом, совпадает значение строк, хранящихся в массиве аргументов inf(). Этот вывод представляет собой evaled в виде аргумента к 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
2
27.01.2020, 20:07

Теги

Похожие вопросы