Coisas que você talvez não saiba sobre Linux, Unix e OS X

Foto: Zack Smith

Já faz bastante tempo que trabalho com Linux e outros unices ao lado de gente muito foda. Ao longo desse período fui aprendendo algumas dicas e macetes que, quando uso na frente de alguns amigos, deixam eles espantados.

São coisas simples que talvez vocês já conheçam mas que vou colocar aqui como referência para as “futuras gerações” 😀

Matando um processo que não quer ser interrompido

Você executa um comando na linha de comando e ele fica travado. Você dá ^C (CTRL-C) e ele não morre? Tente ^\ (CTRL-\).

Complementação enviada pelo meu amigo Rudá Moura: ^C envia um SIGINT, ^\ envia um SIGQUIT, o kill (sem argumentos) envia um SIGTERM e o kill -9 (que deve ser usado somente se você já tentou o SIGTERM) envia um SIGKILL que é o único sinal não interceptável pelo processo.

Sessão SSH travou? Chame o ~

Você deu ssh para um servidor e por algum motivo a sessão ficou pendurada?

Tecla “<ENTER>~.” e a sessão será encerrada imediatamente. Lembre-se que se vc usa um teclado com acentuação deadkeys você precisarar digitar “<ENTER>~<SPACE>.“.

Esse é o comando-til mais legal mas existem outros:

$ man ssh  # procure por "ESCAPE CHARACTERS"

Arquivos com - no início do nome?

Uma brincadeirinha que a gente fazia com a molecada que chegava pra trabalhar era criar um arquivo chamado “-rf ~” em algum lugar na máquina do cara e desafiar: “apague esse arquivo na linha de comando”.

Tem algumas respostas certas para esse desafio mas rm -rf ~ (CUIDADO COM ISSO!) certamente não é uma delas 😀 Tentar fazer escape do “-” ou fazer rm "-rf ~" também não vai funcionar. Os comandos vão interpretar esse sinal como uma opção do próprio comando e não como um argumento do tipo nome de arquivo.

Solução?

rm -- "-rf ~"

Quando colocamos o -- informamos pro comando que todos os parâmetros passados a partir daquele ponto são argumentos para o comando e não opções do comando.

O meu amigo Elvis (EPx) e o Fedalto conhecem outra forma que também permite remover esse diretório:

$ rm -rf ./-rf\ ~

Debugando problemas em software alheio

Você tem um software que simplesmente não está funcionando direito e não dá nenhuma mensagem que te ajude a resolver o problema? Esse software não é seu; foi feito em C; você só tem o binário; etc?

Na minha experiência de vida quase sempre esses problemas acontecem por causas “bobas” como um arquivo de configuração que não está no lugar certo ou está com as permissões incorretas, um processo tentando alocar um recurso que já está sendo usado por outro, etc. Mas como saber disso se a única coisa que aparece pra mim é um enigmático “Segmentation Fault”?

# strace [-p PID|software] [-f]

O strace mostra todas as syscalls que um processo está executando no console. Como é muita informação é sempre legal redirecionar essa saída para um arquivo e analisar depois.

Quando o software caiu você abre o arquivo de log e procura (de trás para frente) por mensagens de erro logo antes do programa morrer. Já resolvi dezenas de problemas assim.

Vale lembrar que essa ferramenta deve ser encarada como um tipo de “último recurso” quando outras técnicas de resolução de problemas já não estiverem funcionando mais.

No OSX o utilitário que imita o strace se chama dtruss e o jeito de usar é bem similar.

Pausando o console

Você executou um tail -f arquivo.log mas os logs chegam numa velocidade que te impedem de analisar as mensagens?

Faça um Pause no terminal: ^S (CTRL-S). Para liberar o Pause: ^Q (CTRL-Q).

Alternando entre jobs

Executou um comando e deu ^Z. Executou outro comando e deu ^Z novamente. Ficou com dois jobs parados, certo? (execute o comando jobs para ver os dois processos parados).

Para trazer um deles devolta para o primeiro plano use o comando:

$ %N  # onde N é o número do job

O Aristeu pediu pra lembrar que esse comando é uma espécie de atalho para o comando fg:

$ fg N

E que, fazendo par com o fg tem o comando bg N que “despausa” o processo e coloca ele pra funcionar em segundo plano.

Se você quer executar um processo direto em segundo plano é só colocar um & no fim da linha:

$ find / > lista_de_arquivos.txt &

É o mesmo que fazer ^Z e bg.

Reexecute comandos

Você digitou um comando grande e chato na linha de comando, precisa reexecutar ele mas ele tá lááá atrás no histórico? Não precisa ficar com a setinha pra cima até cansar. É só usar a !:

$ find . -type f | while read i; do mv "$i" "$i.bak"; done  #ok, eu sei que dá pra melhorar isso mas queria uma linha grande, ok? :D
$ ...
$ ...
$ ...
$ # vamos reexecutar o find|while
$ !fin

Buscando no histórico de comandos

O Thiago Santos, o Aristeu e o toti pediram pra eu acrescentar a busca no histórico. Eu acho que muita gente já sabia desta dica e por isso não coloquei na primeira versão desse artigo. Mas… como tem gente que talvez não conheça aí vai.

Eu uso o modo VI no console (próximo tópico) e para fazer buscas no histórico de comandos eu uso os comandos de busca do próprio vi: <ESC>/string_de_busca. Para repetir a busca basta ir acionando a tecla N.

Por padrão a maioria das distribuições Linux (e alguns Unix) usam o modo emacs e para fazer a mesma busca usa-se o comando CTRL+R. Agora é só digitar a string de busca e <ENTER>. Para repetir a busca use o comando CTRL+R novamente.

Modo VI no console

Tive um amigo que dizia que você não pode se considerar um usuário de VI se usa o modo emacs (default) no console.

Para alternar para o modo VI (erroneamente chamado de modo que bipa pelos detratores do VI) é só digitar:

$ set -o vi

Ou acrescentar as linhas abaixo ao teu ~/.inputrc:

set editing-mode vi
set keymap vi

Nesse modo você usa os comandos do VI navegar no histórico, fazer busca dos comandos, etc. Exemplo: para buscar o comando find no histórico você digita <ESC>/find<ENTER> e para procurar as próximas ocorrências é só ir apertando N. Encontrando o comando é só dar <ENTER> para executar o comando ou I para entrar no modo de edição e alterar o conteúdo da linha.

Mas o mais legal desse modo é que você pode chamar a linha de comando no VI a qualquer momento. Vamos supor que você digitou uma mega linha comprida na linha de comando e começou a ficar complicado de edita-la. No modo VI basta você digitar <ESC>vi e o editor VI será carregado com todo o conteúdo da sua linha de comando.

Se você gravar e sair (:wq) a linha será executada. Se você só sair sem gravar a linha será ignorada.

Usando o comando history

O Gustavo Straube também sugeriu usar o comando history em conjunto com o grep:

$ history | grep 'comando'

Resetando o terminal

Você estava lá trabalhando na linha de comando e acidentalmente deu um cat num arquivo binário achando que lá só tinha texto. Teu terminal ficou todo zoado com símbolos irreconhecíveis no lugar dos caracteres? É só resetar o terminal:

$ reset

Funciona na imensa maioria das vezes. Mas se não funcionar… aí é só matando esse terminal mesmo 😀

Agradecimentos para o toti por ter feito me lembrar dessa dica 😀

Limpando a tela do console

O comando para limpar a tela do console e posicionar o prompt na primeira linha do terminal é:

$ clear

Mas você também pode usar uma combinação de teclas essa função:

  • CTRL-L no Linux
  • CMD-K no Mac OS X

você pode acionar essa combinação de teclas a qualquer momento. Mesmo depois de já ter digitado alguma coisa no prompt. Exemplo:

$ ls 

Vai limpar a tela e manter o comando ls que já foi digitado.

Eu já conhecia e usava isso mas o Adrian C. Miranda me lembro nos comentários.

Último argumento

Essa eu não conhecia e foi passada pelo meu colega Vinicius Assef:

$ git diff path/para/meu/arquivo_que_mudou.py
$ git add !$

O !$ pega o último argumento do último comando digitado no shell.

Para saber mais sobre essa e outras expansões possíveis:

$ man bash  # procure por ^HISTORY EXPANSION

Voltando para o diretório anterior

Essa eu imaginava que todos soubessem mas descobri que muita gente desconhece. O comando cd que altera o diretório corrente aceita o parâmetro - (cd - que faz você voltar para o diretório onde você estava anteriormente.

~/Work/x$ cd ../y
~/Work/y$ cd -
~/Work/x
~/Work/x$ _

Dica: Você também pode usar “git checkout -” no git para voltar para o branch anterior.

Sabe algum macete que não está aqui?

Eu sei de mais alguns outros vários mas não consegui lembrar pra colocar aqui. Conforme for lembrando vou atualizando esse artigo. E você sabe algum? Mande para blog @ osantana (dot) me.

Publicado por

Osvaldo Santana

Desenvolvedor Python e Django, Empreendedor, dono de uma motocicleta esportiva, hobbysta de eletrônica, fã de automobilismo e corinthiano

  • Norival

    alguma maneira de descobrir se um processo foi assassinado? de alguma forma? explico… tem ocorrido de alguns processos simplesmente morrerem… ou voltam para o prompt de comando ou deixam a máquina louquinha/xaropinha… como eu não sou da ”infra”, só estou supeitoso de que andam matando processos aleatoriamente… como poderia identificar melhor a situação ??? Norival… norivalfsouza@gmail.com

  • Uma forma de buscar comandos que eu uso bastante é filtrar o histórico com grep, assim:

    history | grep ‘comando’

  • Clayton

    Sempre vejo o pessoal limpando a tela com o comando “clear”. A combinação Ctrl+L é muito mais prática, limpando inclusive se você estiver dentro do mysql por exemplo.

  • GABRIEL DA MOTTA COSTA

    Uma dica bem legal, uso bastante e recomendo:
    Com as teclas (Ctrl +r). Vc efetua uma pesquisa no histórico de forma reversa… Ajuda muito quando vc precisa visualizar algum comando que vc usou ha pouco tempo.

  • Ou `Cmd + K` / `Cmd + L` no mac 🙂

  • Giovane Nunes

    Uma forma tambem de executar um comando do histórico e colocar no shell. !numero do historico Ex. !1234

  • O S.O. pode matar alguns processos em determinadas situações (ex. falta de memória). Ele sinaliza o processo (manda um SIGNAL) e é possível capturar esse sinal e agir sobre ele.

  • eu raramente uso isso… uso mais o / (uso modo vi) ou ctrl+r (quando estou numa máquina que usa modo emacs).

  • essa dica já está no texto…

  • eu raramente uso isso… uso mais o / (uso modo vi) ou ctrl+r (quando estou numa máquina que usa modo emacs).

  • O difícil é saber/lembrar esse número 🙂 só acionando o (pouco prático) history.

  • Gabriel Duarte

    !! -> executa o último comando do histórico

    # ls
    a.txt b.txt
    # !!
    a.txt b.txt