redirecionando a saída de um comando como se fosse uma entrada de arquivo

3

Eu me vejo sempre tendo que flechar e retroceder na linha de comando para alterar uma parte de um comando anterior que é canalizado para um comando grep ou head ou qualquer outro comando.

Para um exemplo bruto: pesquisando dmesg para uma determinada string e desejando apenas as 5 últimas ocorrências.

Eu faria o acima, de forma que:

dmesg | grep -i USB | tail -n 5

mas, se eu quiser alterar o termo de pesquisa ou o que estou procurando ou a origem, espero que meu cursor volte para a parte relevante da linha. Eu gostaria de movê-lo para o final da linha, de forma que o exemplo acima possa ser representado como (eu sei que isso é incorreto):

tail -n 5 < dmesg | grep -i USB (e eu poderia pesquisar por sda )

como eu disse, este é um exemplo bruto e é indicativo do tipo de coisa que eu gostaria de fazer, mas não exatamente o que eu quero fazer, ou seja. isso não é sobre dmesg ou o uso de grep e tail , mas como interagir entre esses programas colocando a "variável" no final.

Isso poderia ser examinado em mais detalhes sobre como obter o tempo de busca em um inquérito do DNS de tal forma que:

dig google.com | grep msec (vamos mover google.com para o final para que eu possa testar outro domínio) por meio de grep msec < dig google.com

novamente, exemplos ruins. Estou falando mais sobre quando tenho entradas / saídas fluindo entre vários programas

Admito que só tenho uma compreensão básica de tubulação e redirecionamento que pode ser resumida como:

  • tubulação ( | ) usando o stdout de um programa para alimentar o stdin de outro
  • redirecionar ( > ) levando stdout de um programa e alimentando-o em um arquivo ( à parte: ele poderia ser redirecionado para outro lugar além dos únicos óbvios que eu possa imaginar
    > /dev/null ou
    > /dev/sda ou
    > {said file}
    Considerando que piping é a saída do programa como entrada do programa da esquerda para a direita.
  • redirecionamento ( < ) (que chamo de "arquivo como entrada") pegando o conteúdo de um arquivo e usando-o como se tivesse sido digitado na linha de comando
por Madivad 06.03.2016 / 15:50

3 respostas

3

Muitas vezes sou incomodado com a mesma coisa, e há algumas maneiras de lidar com isso:

  1. Basta aceitar, às vezes não vale a pena gastar tempo para contornar isso.

  2. como PSkocik mencionou, você pode usar, por exemplo, tail -n 5 <(dmesg | grep USB)

  3. Torne-se mais hábil com os recursos de edição do seu shell - por exemplo, no bash (e muitos outros programas que usam readline) você pode usar Ctrl A para chegar ao início da linha, ESC f e ESC b para avançar e retroceder uma "palavra" e Ctrl-X Ctrl + E para editar a linha atual em $ EDITOR (por exemplo, vim )

Existem muitos outros comandos de edição disponíveis e readline está totalmente documentado em arquivos .info. Em um sistema Debian, instale o pacote readline-doc . Outras distros podem incluir a documentação no próprio pacote readline ou podem separá-lo como o Debian faz.

Eu também recomendo instalar e usar pinfo para uma experiência mais parecida com o navegador web do lynx (IMO, o navegador GNU info é medonho e quase inutilizável). Se ainda não estiver em sua distro, você pode encontrá-lo no link

  1. readline também tem um modo vi para edição (o padrão é um modo emacs -like), que algumas pessoas preferem.

  2. Em casos simples, você pode usar a substituição rápida: por exemplo, se o último comando que você digitou foi:

dmesg | grep -i USB | tail -n 5

então, digitar ^ USB ^ sda ^ Enter resultaria na execução deste:

dmesg | grep -i sda | tail -n 5

Para mais detalhes, consulte man bash e pesquise HISTORY EXPANSION , especialmente a seção Event Designators .

e sim, fazer isso repetidamente também se torna irritante.

  1. Para casos mais complexos, a melhor solução é escrever um script ou função de shell que faça o que você quer e executar isso em vez de seu longo e complexo pipeline de comandos.

por exemplo. escreva um script chamado dmesg-grep que se pareça com isto:

#! /bin/bash

# regexp to search for is arg 1.  needs to be an extended regexp
# because we're using grep -E aka egrep.
re="$1"

# number of lines to output is optional arg 2 (default 5)
lines=${2:5}

dmesg | grep -iE "$re" | tail -n "$lines"

Então você pode simplesmente executar dmesg-grep usb ou dmesg-grep sda .

Se você fizer isso muito, crie um subdiretório bin do seu diretório pessoal e adicione ~/bin ao seu PATH padrão (por exemplo, em ~/.bash_profile ou ~/.bashrc ) e salve seus scripts lá.

    
por 07.03.2016 / 02:07
3

No shell que suporta <() (bash, ksh, zsh), você pode transformar

$ cmd1 | cmd2 

em

$ cmd2 < <(cmd1)

Estes dois devem ser equivalentes em termos de tubulação. (No entanto, acho que existem algumas pequenas diferenças em termos de como os dois formulários lidam com coisas como grupo de processos e sinais).

Para melhor edição da linha de comando, recomendo que você explore as instalações do seu shell para isso. Por exemplo, o bash tem set -o vi , que permite usar atalhos semelhantes ao vi ou alternar para vim diretamente para editar seu comando com mais eficiência. O set -o emacs padrão usa atalhos do emacs (pesquisa man bash para readline para saber mais sobre eles ( /readline )).

    
por 06.03.2016 / 15:59
1

Você pode pensar que esta é uma resposta lateral, mas muitas vezes a solução é simplesmente usar variáveis em sua linha de comando. Eles não são apenas para scripts de shell. Por exemplo, você está desenvolvendo um "one-liner" complexo por tentativa e erro e tem:

 $ some complex command using value 23 at this point

você quer variar apenas um valor no meio da linha de comando. Uma única edição e, em seguida, a linha torna-se fácil de lembrar sem precisar de mais edições:

 $ a=23
 $ some complex command using value "$a" at this point
 $ a=37
 $ some complex command using value "$a" at this point
 $ a=42
 $ some complex command using value "$a" at this point

É ainda melhor quando você precisa de $a em dois ou mais lugares no comando, como em um diretório ou nome de arquivo.

    
por 06.03.2016 / 16:42