Atalho do teclado do histórico do Bash para! *

8

No Bash, existem alguns operadores úteis para repetir partes do último comando:

  • !^ expande para o primeiro argumento do comando anterior, por exemplo,

    $ echo one "two three"
    one two three
    $ echo !^
    echo one
    one
  • !$ expande para o último argumento do comando anterior, por exemplo,

    $ echo one "two three"
    one two three
    $ echo !$
    echo "two three"
    two three
  • !* expande para todos os argumentos do comando anterior, por exemplo,

    $ echo one "two three"
    one two three
    $ echo !*
    echo one "two three"
    one two three

(Pelo que entendi, esses são açúcares sintáticos para !!:^, !!:$e !!:*respectivamente, onde !!é um designador de eventos que se expande para o comando anterior e ^, $e *são designadores de palavras, consulte o Manual de Referência do Bash ou man bash.)

Estes são frequentemente bastante úteis. Mas fica ainda mais legal com os atalhos do teclado:

  • Quando você pressiona Alt+ .ou Alt+ _, o último argumento do comando anterior é inserido no comando atual, da mesma forma como se você tivesse escrito !$naquele momento.

  • Também é possível pressionar Alt+ Ctrl+ ypara inserir o primeiro argumento do comando anterior, como se você tivesse escrito !^naquele momento.

(Veja a GNU Readline Library ou info readline.)

Costumo preferir os atalhos de teclado aos operadores de histórico do Bash, porque posso ver o que estou inserindo antes de executar o comando. No entanto, não parece haver um atalho que me permita inserir todas as palavras do comando anterior, ou seja, aquele que executa !*o trabalho. Pelo menos eu não consegui encontrar.

Existe um atalho? Caso contrário, é possível configurar a biblioteca readline para adicionar uma e como?

Malte Skoruppa
fonte
AFAIK, os atalhos de teclado são tratados pelo emulador de terminal. Então, suponho que você esteja usando o gnome-terminal?
Seth
1
Em zsh, se você digitar echo !*e pressionar TAB, terá o efeito desejado. Em geral, o TAB enquanto estiver na linha de leitura expandirá todo o expansível. Muito conveniente; provavelmente bash terá alguma configuração para o mesmo efeito? @ Set, acho que esta é a linha de leitura do bash, não o emulador de terminal - embora não tenha certeza.
Rmano 25/03
2
@Seth Não, os atalhos do Q são tratados pelo bash. Você pode procurar por 'Comandos para manipular a história' em man bash( em algum lugar na linha 3030)
Radu Rădeanu
@ RaduRădeanu Oh, interessante! Eu não sabia disso. Meu mau por más suposições.
Seth
1
\e.e \e_são mapeados para a função readline yank-last-arge \e\C-ysão mapeados para yank-nth-arg. Infelizmente, parece não haver um comando (único) que adicione vários argumentos anteriores de uma só vez.
Adaephon 25/03

Respostas:

5

Se você observar a saída do seguinte comando:

bind -l

ou melhor para:

bind -l | grep arg

você pode ver que não existe nenhuma função de linha de leitura para todos os argumentos, como, por exemplo, o yank-last-argúltimo argumento - que pode inserir o último argumento no comando anterior (a última palavra da entrada do histórico anterior). Portanto, se essa função não existir, provavelmente não existe um atalho para realizar o que você deseja.

Vamos tentar criar uma abordagem para o seu pedido ...

Primeiro, observe, por exemplo, a saída do seguinte comando:

bind -p | grep yank-nth-arg

A saída é:

"\e\C-y": yank-nth-arg

e pode ser traduzido da seguinte forma: yank-nth-arg(que insere o primeiro argumento no comando anterior - com um argumento n, insira o enésimo argumento do comando anterior) está vinculado a Alt+ Ctrl+ y.

Da mesma maneira, pode ser interpretada qualquer linha da saída do bind -pcomando.

Agora preste atenção nos seguintes cenários:

  • Se você definir a seguinte ligação:

    bind '"\ea": "\e2\e."'

    Alt+ Aserá mapeado para Alt+ 2Alt+, .que é mapeado para inserir o segundo argumento do comando anterior. Portanto, depois que você pressionar Alt+ A, o segundo argumento do comando anterior será inserido no comando atual.

  • Se você definir:

    bind '"\ea": "\e1\e. \e2\e."'

    Depois de pressionar Alt+ A, os dois primeiros argumentos do comando anterior são inseridos no comando atual. Se o número de argumentos do comando anterior for no máximo 2, é claro que todo o comando anterior será inserido no comando atual.

  • Se você definir:

    bind '"\ea": "\e1\e. \e2\e. \e3\e."'

    Depois de pressionar Alt+ A, os três primeiros argumentos do comando anterior são inseridos no comando atual. Se o número de argumentos do comando anterior for no máximo 3 (como no seu caso), é claro que todo o comando anterior será inserido no comando atual.

  • E assim por diante.

Para os 10 primeiros argumentos, você pode usar:

bind '"\ea": "\e1\e. \e2\e. \e3\e. \e4\e. \e5\e. \e6\e. \e7\e. \e8\e. \e9\e. \e1\e0\e."'

E acho que isso é longo o suficiente, desde que eu não use comandos com muita frequência com tantos argumentos.

Para torná-lo persistente, adicione a seguinte linha ao seu ~/.inputrcarquivo:

"\ea": "\e1\e. \e2\e. \e3\e. \e4\e. \e5\e. \e6\e. \e7\e. \e8\e. \e9\e. \e1\e0\e."

Neste exemplo, escolhi Alt+ Apara inserir todos os argumentos (se o número de argumentos não for maior que 10) do comando anterior, mas você pode escolher qualquer outra combinação substituindo a \easequência no comando anterior .

Recursos:

Radu Rădeanu
fonte
Bem, é um tanto imprudente, e funcionará apenas para um número limitado de argumentos, mas parece ser o mais próximo que podemos facilmente chegar - eu aceito;) Na verdade, acabei de dar uma olhada no código-fonte do readline. À primeira vista, parece que no arquivo funmap.c, a função yank-nth-argé mapeada para a função C rl_yank_nth_arg, que por sua vez é definida em kill.c. Analogamente para yank-last-arg. É claro que seria possível estender a linha de leitura com essa funcionalidade, mas não quero fazer isso; Prefiro meu readline a ser gerido pela apt, e esse recurso não que importante;)
Malte Skoruppa