Загальна проблема
Я хочу написати сценарій, який взаємодіє з користувачем, хоча він знаходиться в середині ланцюга труб.
Конкретний приклад
Конкретніше, він займає file
або stdin
, відображає рядки (з номерами рядків), просить користувача ввести вибір або номери рядків, а потім друкує відповідні рядки stdout
. Давайте назвемо цей сценарій selector
. Тоді в основному я хочу вміти це робити
grep abc foo | selector > myfile.tmp
Якщо foo
містить
blabcbla
foo abc bar
quux
xyzzy abc
потім selector
подає мені (на терміналі, не в myfile.tmp
!) з опціями
1) blabcbla
2) foo abc bar
3) xyzzy abc
Select options:
після чого я набираю
2-3
і в кінцевому підсумку
foo abc bar
xyzzy abc
як зміст myfile.tmp
.
У мене запущений і запущений селекторний сценарій, і в основному він працює відмінно, якщо я не переспрямовую введення та виведення. Тому
selector foo
поводиться так, як я хочу. Однак, з'єднуючи речі разом, як у наведеному вище прикладі, selector
друкується представлені параметри myfile.tmp
та намагається прочитати виділення із введеного даних.
Мій підхід
Я намагався використовувати -u
прапор read
, як у
exec 4< /proc/$PPID/fd/0
exec 4> /proc/$PPID/fd/1
nl $INPUT >4
read -u4 -p"Select options: "
але це не робить те, що я сподівався.
З: Як отримати фактичну взаємодію з користувачем?
cmd | { some processing; read var </dev/tty; } | cmd
alias selector='{ TMPFILE=$(mktemp); cat > $TMPFILE; nl -s") " $TMPFILE | column -c $(tput cols); read -e -p"Select options: " < /dev/tty; rangeselect -v range="$REPLY" $TMPFILE; rm $TMPFILE; }'
це працює досить непогано. Однак grep b foo | selector | wc -l
тут перерви. Будь-які ідеї, як це виправити? До речі, те, rangeselect
що я використав, можна знайти на pastebin.com/VAxTSSHs . Це простий сценарій AWK, який друкує рядки файлу, що відповідають заданому діапазону рядків. (Діапазон може бути таким, як "3-10, 12,14,16-20".)
alias
це, скоріше selector() { all of that stuff...; }
у функцію. alias
es перейменувати прості команди, тоді як функції пакують складні команди в одну просту команду .