O histórico de comandos é uma das funcionalidades mais poderosas e subutilizadas do shell Bash. Ele permite que você recupere, reutilize e gerencie comandos digitados anteriormente, economizando tempo e evitando erros de digitação. Dominar o histórico é essencial para qualquer pessoa que trabalhe com o terminal Linux, pois transforma a interação com o shell em uma experiência muito mais eficiente.

Nesta aula, vamos explorar desde o básico, como visualizar e navegar pelo histórico, até técnicas avançadas de busca reversa e expansão. Também veremos como configurar o histórico para que ele se adapte ao seu fluxo de trabalho, incluindo variáveis de ambiente e opções do shell. Ao final, você terá um conjunto de habilidades práticas que poderá aplicar imediatamente no seu dia a dia.

Comando history

O comando history exibe uma lista numerada dos comandos executados no shell atual. Cada linha do histórico é precedida por um número de evento, que pode ser usado para referenciar comandos específicos em operações de expansão. Por padrão, o Bash mantém um histórico de comandos em memória durante a sessão e, ao final, salva-o no arquivo ~/.bash_history.

Para visualizar o histórico, basta digitar history no terminal. Você pode limitar a saída usando um argumento numérico, por exemplo, history 20 mostra os últimos 20 comandos. Outra forma de navegar pelo histórico é usando as setas do teclado: ↑ (seta para cima) recupera o comando anterior e ↓ (seta para baixo) avança para o próximo. Essas teclas são atalhos para as funções previous-history e next-history do Bash.

Exemplo de uso do comando history:

$ history 5
  501  ls -la
  502  cd /var/log
  503  tail -f syslog
  504  grep "error" syslog
  505  history 5

O histórico também pode ser manipulado com o comando fc (fix command), que permite listar, editar e reexecutar comandos. Por exemplo, fc -l lista o histórico, e fc -s 502 reexecuta o comando de número 502. Embora fc seja poderoso, muitos usuários preferem os atalhos diretos que veremos a seguir.

Busca reversa (Ctrl+R)

A busca reversa é um recurso que permite pesquisar comandos no histórico de forma incremental. Ao pressionar Ctrl+R, o Bash entra no modo de busca reversa: você começa a digitar parte do comando e o shell exibe o comando mais recente que contém o texto digitado. Conforme você digita, a busca é atualizada em tempo real. Para aceitar o comando exibido, pressione Enter; para editar antes de executar, use as setas ou Esc para sair do modo de busca mantendo o comando no prompt.

Se houver múltiplos comandos correspondentes, você pode navegar pelos resultados pressionando Ctrl+R repetidamente para retroceder no histórico. Para buscar em ordem cronológica inversa (do mais antigo para o mais recente), use Ctrl+S (se estiver habilitado no terminal).

Exemplo de busca reversa:

$ (Ctrl+R) grep error
(reverse-i-search)`grep error': grep "error" syslog

Isso é extremamente útil quando você lembra apenas parte de um comando longo, como um comando com muitas opções. A busca reversa é uma das maneiras mais rápidas de reutilizar comandos complexos sem precisar redigitá-los.

Expansão (!!)

A expansão de histórico permite reutilizar comandos anteriores usando referências especiais. O mais comum é !!, que expande para o último comando executado. Por exemplo, se você digitou um comando sem sudo e recebeu um erro de permissão, pode executar sudo !! para repetir o último comando com privilégios administrativos.

Outras expansões úteis incluem:

  • !n: executa o comando de número n do histórico (por exemplo, !502).
  • !-n: executa o comando n posições atrás no histórico (por exemplo, !-2 executa o penúltimo comando).
  • !string: executa o comando mais recente que começa com string (por exemplo, !grep).
  • !?string: executa o comando mais recente que contém string em qualquer lugar.
  • ^string1^string2: repete o último comando substituindo string1 por string2.

Exemplo de uso de !!:

$ apt update
Permission denied (are you root?)
$ sudo !!
sudo apt update
[sudo] password for user: 
...

Essas expansões são processadas pelo shell antes da execução, então você pode combiná-las com outros comandos. Por exemplo, !grep | tail -n 5 executa o último comando grep e envia a saída para o tail.

Configuração

O comportamento do histórico pode ser ajustado por meio de variáveis de ambiente e opções do shell. As principais variáveis são:

  • HISTSIZE: número de comandos mantidos na memória durante a sessão (padrão: 1000).
  • HISTFILESIZE: número de linhas salvas no arquivo de histórico (padrão: 2000).
  • HISTFILE: caminho do arquivo de histórico (padrão: ~/.bash_history).
  • HISTCONTROL: controla como os comandos são gravados (valores comuns: ignoredups, ignorespace, erasedups, ignoreboth).
  • HISTIGNORE: lista de padrões (separados por :) que não devem ser salvos.

Por exemplo, para ignorar comandos duplicados e comandos que começam com espaço, adicione ao seu ~/.bashrc:

export HISTCONTROL=ignoreboth
export HISTSIZE=10000
export HISTFILESIZE=20000
export HISTIGNORE="ls:cd:history"

Além das variáveis, você pode usar o comando shopt para habilitar opções como histappend, que faz com que o histórico seja anexado ao arquivo em vez de sobrescrevê-lo a cada sessão. Isso evita a perda de histórico quando você abre múltiplos terminais. Para ativar:

shopt -s histappend

Outra opção útil é cmdhist, que salva comandos multilinha como uma única entrada no histórico. Para habilitar:

shopt -s cmdhist

Essas configurações podem ser colocadas no ~/.bashrc para que sejam aplicadas em todas as sessões interativas. Lembre-se de recarregar o arquivo com source ~/.bashrc ou abrir um novo terminal.

Boas práticas

Para aproveitar ao máximo o histórico, considere as seguintes recomendações:

  • Use HISTCONTROL=ignoreboth para evitar duplicatas e comandos sensíveis com espaço inicial.
  • Defina tamanhos generosos de histórico (HISTSIZE e HISTFILESIZE) para reter mais comandos.
  • Ative histappend para preservar o histórico entre múltiplos terminais.
  • Utilize a busca reversa (Ctrl+R) com frequência para recuperar comandos longos.
  • Combine expansões com outros comandos para criar pipelines poderosos.
  • Limpe o histórico periodicamente com history -c (limpa a memória) e history -w (grava no arquivo) para manter a privacidade.

Referências

Exercícios

  1. Explique a diferença entre HISTSIZE e HISTFILESIZE e como eles afetam o histórico.
  2. ✓ Resposta: HISTSIZE define o número máximo de comandos mantidos na memória durante a sessão, enquanto HISTFILESIZE define o número máximo de linhas gravadas no arquivo de histórico. O histórico em memória é usado para navegação e busca; ao final da sessão, ele é salvo no arquivo, respeitando HISTFILESIZE.
  3. Qual comando você usaria para executar o comando de número 123 do histórico? E para executar o penúltimo comando?
  4. ✓ Resposta: Para executar o comando de número 123, use !123. Para executar o penúltimo comando, use !-2.
  5. Como você pode evitar que comandos que começam com espaço sejam salvos no histórico?
  6. ✓ Resposta: Definindo HISTCONTROL=ignorespace (ou ignoreboth, que também ignora duplicatas). Assim, comandos que começam com espaço não são gravados.
  7. Qual é a diferença entre ! e !! na expansão de histórico?
  8. ✓ Resposta: !! expande para o último comando executado, enquanto ! sozinho não é uma expansão válida; você precisa especificar um número, string ou -n (por exemplo, !123, !grep, !-2).
  9. Explique como a busca reversa (Ctrl+R) funciona e dê um exemplo de uso.
  10. ✓ Resposta: A busca reversa permite pesquisar comandos no histórico de forma incremental. Pressione Ctrl+R e comece a digitar; o Bash mostra o comando correspondente mais recente. Pressione Ctrl+R novamente para ver resultados anteriores. Exemplo: se você digitou grep "error" syslog anteriormente, pressione Ctrl+R, digite grep error e o comando aparecerá; pressione Enter para executá-lo.