reutilize a última saída do comando no índice / line-num

2
ls

exibe:

entry1
entry2
entry3

Como posso reutilizar a saída acima (nem todas as entradas, mas a entrada em uma determinada linha, digamos n) no próximo comando shell?

Algo como:

vi $(!!)@3

Deve significar:

vi entry3
    
por Madhavan Kumar 06.06.2015 / 10:55

3 respostas

2

Você não pode reutilizar diretamente a saída: ela é armazenada apenas na memória de vídeo, como um monte de pixels; ou talvez na memória do emulador de terminal, mas também não há nenhuma maneira conveniente de recuperá-lo. O que você pode fazer é executar o comando novamente e capturar sua saída desta vez. Isso é o que o !! faz.

Em zsh, use sinalizadores de expansão de parâmetro e substituições aninhadas para extrair o linha escolhida. Como alternativa, você pode permitir que um utilitário externo faça a divisão, que fica mais fácil de digitar.

vi "${${(f)$(!!)}[3]}"
vi "$(!! | awk NR==3)"

Este é um dos poucos casos em que você precisa de aspas duplas mesmo em zsh, caso contrário, a saída do comando será dividida em componentes delimitados por espaços em branco. Se os componentes delimitados por espaços em branco estiverem bem, você poderá usar um comando muito mais curto:

vi ${$(!!)[3]}
    
por 06.06.2015 / 23:43
1

Uma maneira clássica de extrair uma linha específica de uma saída é combinando os comandos head e tail :

LINE=3
ls | head -n $LINE | tail -n 1
  • O comando ls gera a saída inicial,
  • head -n $LINE mantém apenas as primeiras $LINE linhas desta saída original,
  • tail -n 1 mantém apenas a última linha da saída do comando head .

No final, apenas a linha na posição determinada permanecerá.

Então, para continuar com o seu exemplo, digamos que essa saída contenha o nome de um arquivo que você precisa editar usando vi , você pode usar essa saída graças a essas sintaxes:

vi $(ls | head -n $LINE | tail -n 1)
vi 'ls | head -n $LINE | tail -n 1'

O primeiro é o preferido devido à sua legibilidade. O segundo é o histórico compatível com sistemas mais antigos.

Como última nota, algumas vezes acontece que o comando inicial (um simples ls neste exemplo) pode levar tempo e consumir recursos para ser executado. Se você precisar pegar várias linhas de sua saída, não hesite em armazenar sua saída em uma variável ou em um arquivo, para que ele precise ser executado apenas uma vez:

# Using a variable:
my_ls=$(ls)
vi $(echo "$my_ls" | head -n 3 | tail -n 1)
vi $(echo "$my_ls" | head -n 26 | tail -n 1)
vi $(echo "$my_ls" | head -n 1900 | tail -n 1)

# Using a file:
ls >./my_ls
vi $(cat ./my_ls | head -n 3 | tail -n 1)
vi $(cat ./my_ls | head -n 26 | tail -n 1)
vi $(cat ./my_ls | head -n 1900 | tail -n 1)
    
por 06.06.2015 / 11:21
0

Eu não tenho muita experiência com o zsh, mas uma maneira possível pode ser:

$ p() { i=$1 && shift && a=("${(@f)$("$@")}") && echo "${a[$i]}" }
$ ls
entry1
entry2
entry3
$ echo $(p 3 !!)
echo $(p 3 ls)
entry3

Para o bash:

$ p() { i=$1 && shift && IFS=$'\n' a=($("$@")) && echo "${a[$((i-1))]}"; }

Admito que é bastante incômodo sintaxe e sem verificações de erros.

    
por 06.06.2015 / 12:03