Como canalizar um único item de uma saída de comando para outro comando?

3

Exemplo básico usando o grep (observe que o grep não seria meu único caso de uso para isso):

$ grep -Irl "foo"
path/to/directory/help.js
path/to/directory/config.js
path/to/directory/task.js

Agora quero abrir o arquivo config.js no Vi. Meu método normal seria:

$ vi path/to/directory/config.js

que eu tive que digitar à mão com a ajuda do preenchimento de tabulação, ou eu destaquei o nome do arquivo do resultado do grep e o copiei / colei.

Mas eu gostaria de poder visualizar o arquivo apenas especificando que este foi o segundo resultado no comando grep. Então, algo como:

$ grep -Irl "foo" | xargs vi 2

Obviamente, xargs não funcionariam assim, era apenas um exemplo. Mas estou tentando descobrir se existe uma maneira de usar xargs (ou qualquer outro utilitário) para conseguir isso e não estou achando.

Algo que um colega de equipe sugeriu para mim foi usar head e tail juntos, assim:

$ grep -Irl "foo" | tail -n 1 | xargs vi

recuperaria task.js e

$ grep -Irl "foo" | head -n 2 | tail -n 1 | xargs vi

recuperaria o config.js. Imaginando se existe um método menos detalhado.

    
por jewbix.cube 02.11.2017 / 22:22

3 respostas

1

Que tal

   vi $( grep -IrL "foo" | awk "NR==3" )

Isso usa o AWK para encontrar a linha apropriada. A saída é então usada como um argumento de linha de comando para o vi.

Sou oldschool, então prefiro a versão equivalente, mas ligeiramente desaprovada -

 vi ' grep -IrL "foo" | awk "NR==3" '
    
por 02.11.2017 / 22:42
2

Não é bem o que foi solicitado porque não usa um pipeline no vi, mas usando sed :

vi $( grep -Irl "foo" | sed -n '2 p')

    
por 02.11.2017 / 22:58
1

Eu escrevi uma função wrapper para essa finalidade, que você pode usar se quiser reutilizar uma linha de saída de um comando.

Primeiro a função para bash :

catch() {
   out="$($@)" 
   nl <<< "$out"
   read -a r -d '\n' <<< "$out"
   r=("dummy" "${r[@]}")
}

Então, para zsh :

catch () {
   out="$($@)" 
   nl <<< "$out"
   r=("${(@f)out}") 
}

O uso é para as duas variantes iguais. Primeiro, execute o comando desejado, prefixado com catch , que apresentará a saída do comando com uma boa numeração:

$ catch grep -Irl "foo"
   1  path/to/dir/task.js
   2  path/to/dir/help.js
   3  path/to/dir/config.js
$

Agora, você pode reutilizar qualquer linha em um comando a seguir usando o parâmetro de matriz $r , por exemplo,

$ wc -c ${r[2]}
14044 path/to/dir/help.js

Em zsh você pode omitir as chaves ( wc -c $r[2] ) mas em bash você precisa delas infelizmente.

Algumas ressalvas que vêm à minha mente:

  • a saída só é exibida após o término do comando
  • caracteres estranhos na saída podem produzir um comportamento errático (por exemplo, novas linhas no nome do arquivo)
  • apenas a saída para STDOUT é capturada (se alguma saída for gravada em STDERR, ela será desfeita no console e ignorada em $r )
por 23.12.2017 / 11:55