Problema general
Quiero escribir un script que interactúe con el usuario a pesar de que está en medio de una cadena de tuberías.
Ejemplo concreto
Concretamente, toma una file
o stdin
, muestra líneas (con números de línea), le pide al usuario que ingrese una selección o números de línea, y luego imprime las líneas correspondientes en stdout
. Llamemos a este script selector
. Entonces, básicamente, quiero poder hacer
grep abc foo | selector > myfile.tmp
Si foo
contiene
blabcbla
foo abc bar
quux
xyzzy abc
luego selector
me presenta (¡en la terminal, no dentro myfile.tmp
!) con opciones
1) blabcbla
2) foo abc bar
3) xyzzy abc
Select options:
después de lo cual escribo
2-3
y terminar con
foo abc bar
xyzzy abc
como contenido de myfile.tmp
.
Tengo un script selector en funcionamiento, y básicamente funciona perfectamente si no redirijo la entrada y la salida. Entonces
selector foo
se comporta como yo quiero. Sin embargo, al unir elementos como en el ejemplo anterior, selector
imprime las opciones presentadas myfile.tmp
e intenta leer una selección de la entrada grepped.
Mi acercamiento
He tratado de usar la -u
bandera de read
, como en
exec 4< /proc/$PPID/fd/0
exec 4> /proc/$PPID/fd/1
nl $INPUT >4
read -u4 -p"Select options: "
Pero esto no hace lo que esperaba.
P: ¿Cómo obtengo la interacción real del usuario?
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; }'
que funciona bastante bien. Sin embargo se grep b foo | selector | wc -l
rompe por aquí. ¿Hay alguna idea de cómo arreglar eso? Por cierto, el rangeselect
que usé se puede encontrar en pastebin.com/VAxTSSHs . Es un script AWK simple que imprime las líneas de un archivo correspondiente a un rango dado de números de lino. (Los rangos pueden ser cosas como "3-10, 12,14,16-20".)
alias
eso, más bien selector() { all of that stuff...; }
en una función. alias
es renombrar comandos simples mientras que las funciones empaquetan un comando compuesto en un solo comando simple .