Expansão de Histórico: Reutilizando Comandos com !! e !$

Expansão de Histórico: Reutilizando Comandos com !! e !$

O Que Você Vai Aprender

  • Que a expansão de histórico é uma "sintaxe para recuperar comandos passados"
  • Como reutilizar um comando ou argumento instantaneamente com !! / !$
  • Como extrair itens específicos do histórico com !string / !:n / :h :t :r
  • Como a substituição rápida ^old^new^ funciona, e como se manter seguro com histverify
Lina: Linny-senpai, eu continuo vendo coisas como sudo !! e cd !$. O que é essa marca !?
Veterano Linny: Isso é "expansão de histórico," um recurso do bash. Quando você digita uma sintaxe que começa com !, o bash recupera um comando ou argumento passado para que você possa reutilizá-lo. Economiza muita digitação.

1. O Que é Expansão de Histórico?

Conclusão: A expansão de histórico é um recurso do bash que expande a sintaxe ! em um comando ou argumento passado, reduzindo digitação e erros de reentrada.

Lina: O que "expansão" realmente significa?
Veterano Linny: Antes de executar um comando, o bash substitui sintaxes como !! pelo texto real do comando. Por exemplo, !! se expande para seu comando anterior inteiro.

A expansão de histórico é construída a partir de três tipos de partes.

Parte Função Exemplo
Event designator Qual comando recuperar !! / !42
Word designator Qual palavra desse comando extrair !$ / !^
Modifier Como transformar a palavra extraída :h / :t

A expansão de histórico funciona principalmente no shellUm programa interativo que interpreta os comandos digitados e os executa. bash interativo. Ela é desativada por padrão dentro de scripts, então lembre-se: "útil interativamente, mas não escreva em scripts."

2. Event Designators: Qual Comando Recuperar

Conclusão: !! é o comando anterior, !n é o número n do histórico, !string é o comando mais recente que começa com string, e !?string? é o mais recente que contém string.

Lina: Então primeiro eu escolho "qual comando recuperar."
Veterano Linny: Certo. O mais comum é !!, o comando anterior. É o truque clássico quando você esqueceu o sudo.

!! -- O Comando Anterior Inteiro

$ apt update
E: Could not open lock file /var/lib/dpkg/lock-frontend ...

$ sudo !!
sudo apt update

!n / !-n -- Por Número do Histórico

$ history | grep tar
  765  tar -czf backup.tar.gz /etc

$ !765
tar -czf backup.tar.gz /etc

!n recupera o número n do histórico, e !-n recupera "n comandos atrás" (!-1 é o mesmo que !!).

!string -- Comando Mais Recente que Começa com string

$ !ssh
ssh user@server

!string re-executa o comando mais recente que começa com string.

!?string? -- Comando Mais Recente que Contém string

$ !?server?
ssh user@server

!?string? encontra o comando mais recente que contém string em qualquer lugar, não apenas no início. Essa é a diferença em relação ao !string.

!string executa imediatamente sem confirmação. Pode recuperar um comando mais antigo que você não pretendia, então quando estiver em dúvida, verifique o resultado primeiro com :p (apenas imprimir), coberto a seguir.

3. Word Designators: Extraindo Argumentos

Conclusão: !$ é o último argumento, !^ o primeiro, !* todos os argumentos, e !:n a n-ésima palavra. Eles evitam redigitar caminhos longos.

Lina: Às vezes eu quero reutilizar apenas um argumento, não o comando inteiro.
Veterano Linny: É para isso que servem os word designators. !$ é "o último argumento do comando anterior," então você evita redigitar um caminhoUma sequência de texto que descreve a localização de um arquivo ou diretório. longo.

!$ -- O Último Argumento

$ mkdir -p /var/log/myapp
$ cd !$
cd /var/log/myapp

!^ e !* -- Primeiro Argumento / Todos os Argumentos

$ cp config.yml config.yml.bak
$ vim !^
vim config.yml

!^ é o primeiro argumento, e !* é cada argumento exceto o nome do comando.

!:n -- A n-ésima Palavra

As palavras são numeradas a partir de 0, onde 0 é o próprio nome do comando.

$ cp src.txt dst.txt
$ echo !:1
echo src.txt
$ echo !:2
echo dst.txt
Word designator Significado
!^ Primeiro argumento (igual a !:1)
!$ Último argumento
!* Todos os argumentos (!:1-$)
!:0 O próprio nome do comando
!:n A n-ésima palavra
!:n-m Palavras de n até m

!$ e similares implicitamente se referem ao comando anterior. Para extrair um argumento de um comando diferente, combine-os com um event designator, como !ssh:$.

4. Modifiers: Transformando a Palavra

Conclusão: :h é a parte do diretórioUm local que organiza arquivos. É a mesma ideia da "pasta" do Windows ou macOS., :t o nome do arquivo, :r remove a extensão, :e mantém apenas a extensão, e :p imprime sem executar.

Lina: Às vezes eu quero apenas o "diretório" ou apenas o "nome do arquivo" de um caminho.
Veterano Linny: Os modifiers cuidam disso. Adicione :h ou :t após um word designator para dividir um caminho em partes.
$ ls /var/log/syslog
$ echo !$:h
echo /var/log
$ echo !$:t
echo syslog
Modifier Ação Exemplo (/var/log/app.log)
:h head: remover o componente final (dir) /var/log
:t tail: manter apenas o componente final app.log
:r rootA conta de administrador especial que pode fazer qualquer coisa no sistema.: remover a extensão /var/log/app
:e extension: manter apenas a extensão log
:p print: mostrar a expansão apenas (sem exec) --

Use :p para Visualizar a Expansão

$ !ssh:p
ssh user@server

Com :p, a expansão de histórico imprime o resultado sem executá-lo. A expansão é adicionada ao seu histórico, então você pode revisá-la e depois executá-la com !!.

Ao recuperar comandos com rm ou sudo via !string, adquira o hábito de verificar o resultado com :p primeiro para evitar acidentes.

5. Substituição Rápida: ^old^new^

Conclusão: ^old^new^ re-executa o comando anterior com o primeiro old substituído por new. Perfeito para corrigir um erro de digitação.

Lina: Quando eu digito errado apenas uma parte do comando anterior, redigitar tudo é irritante.
Veterano Linny: Use ^old^new^. Ele re-executa o comando anterior com old substituído por new. É a correção padrão para erros de digitação.
$ cat /etc/hosst
cat: /etc/hosst: No such file or directory

$ ^hosst^hosts^
cat /etc/hosts

^old^new^ é um atalho para !!:s/old/new/ e substitui apenas a primeira correspondência. Para substituir todas, use !!:gs/old/new/.

O ^ final é opcional (^hosst^hosts também funciona). Mas se você quiser adicionar mais texto após a substituição, escreva o ^ final explicitamente.

6. Mantendo-se Seguro com histverify

Conclusão: Com shopt -s histverify, a expansão de histórico não é executada imediatamente; ela se expande na linha de edição para que você possa confirmar antes de pressionar Enter.

Lina: Me assusta um pouco que !! execute sem confirmação.
Veterano Linny: histverify resolve isso. Com ele ativado, o resultado expandido de !! aparece na sua linha de entrada primeiro, e nada executa até você pressionar Enter.

Adicione esta única linha ao ~/.bashrc.

shopt -s histverify

Depois recarregue com source ~/.bashrc. A partir de agora, digitar !! ou !string mostra o comando expandido na linha de entrada para que você possa revisar e editar antes de executar com Enter.

histverify é uma rede de segurança contra executar comandos destrutivos por acidente. Se você usa expansão de histórico diariamente, ativá-lo traz tranquilidade.

7. Resumo

Conclusão: Combine as três partes -- event designator, word designator e modifier -- para reutilizar comandos passados livremente.

Aqui está um resumo rápido da sintaxe principal de expansão de histórico.

Sintaxe Significado
!! O comando anterior inteiro
!n / !-n Número n do histórico / n comandos atrás
!string Comando mais recente que começa com string
!$ / !^ Último argumento / primeiro argumento
!* Todos os argumentos
!$:h :t Diretório / nome do arquivo de um caminho
^old^new^ Re-executar comando anterior, substituído
!!:p Imprimir a expansão apenas (sem executar)
Lina: Um ! oferece tantas formas de recuperar comandos! Vou começar com !! e !$.
Veterano Linny: Isso é suficiente. Quando estiver confortável, adicione !string e ^old^new^, e sua digitação ficará cada vez mais rápida.

Próximas Leituras