Eu escrevi uma pequena função: ela não responderá sobre o que você pediu para encadear o encanamento, mas resolverá o seu problema.
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)"
)
A função vira todos os argumentos que você deu imediatamente para grep
. Se você usar um shell glob para especificar os arquivos que ele deve ler, ele retornará todas as correspondências em todos os arquivos, começando com o primeiro na ordem glob e terminando com a última correspondência.
grep
passa sua saída para nl
, que numera cada linha e que passa sua saída para tee
, o que duplica sua saída para stdout
e para /dev/tty
. Isso significa que a saída do pipeline é impressa simultaneamente para a matriz de argumentos da função, onde é dividida em \n
ewlines e para o terminal como funciona.
Em seguida, a função _in()
tentará read
em uma seleção se houver pelo menos um resultado da ação anterior no máximo cinco vezes. A seleção pode consistir em apenas números separados por espaços, ou então intervalos de números separados por -
. Se qualquer outra coisa for read
(incluindo uma linha em branco) , ele tentará novamente - mas apenas, como antes, no máximo cinco vezes.
Por último, a função _out()
analisa a seleção do usuário e expande os intervalos nele. Ele imprime seus resultados na forma "${[num]}"
para cada um - correspondendo, assim, ao valor das linhas armazenadas na matriz arg de inf()
. Essa saída é eval
ed como args para printf
, portanto, imprime apenas as linhas selecionadas pelo usuário.
É explicitamente read
do terminal e imprime apenas o menu Select:
para stderr
e, portanto, é muito fácil de usar. Por exemplo, os seguintes trabalhos:
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
Mas você pode usar qualquer opção que você daria a grep
e qualquer número de nomes de arquivos que você possa entregar também. Ou seja, você pode usar qualquer um, exceto um tipo - como um efeito colateral de sua entrada de análise com $IFS
, isso não funcionará se você estiver procurando por linhas em branco. Mas quem gostaria de selecionar uma lista numerada de linhas em branco?
Por último, note que, como isso funciona traduzindo diretamente a entrada numérica do usuário nos parâmetros posicionais numéricos armazenados na matriz de argumentos da função, a saída será o que o usuário selecionar, quantas vezes o usuário a selecionar, e em qualquer ordem que o usuário selecione.
Por exemplo:
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