Qual é o seu truque de linha de comando favorito usando Bash?[fechado]
-
09-06-2019 - |
Pergunta
Todos nós sabemos como usar <ctrl>-R
para reverter a pesquisa no histórico, mas você sabia que pode usar <ctrl>-S
para encaminhar a pesquisa se você definir stty stop ""
?Além disso, você já tentou executar bind -p para ver todos os atalhos de teclado listados?Existem mais de 455 no Mac OS X por padrão.
Qual é o seu truque obscuro, atalho de teclado ou configuração de shopt favorito usando o bash?
Solução 7
Ao executar comandos, às vezes quero executar um comando com os argumentos anteriores.Para fazer isso, você pode usar este atalho:
$ mkdir /tmp/new
$ cd !!:*
Ocasionalmente, em vez de usar find, quebrarei um loop de uma linha se precisar executar vários comandos em uma lista de arquivos.
for file in *.wav; do lame "$file" "$(basename "$file" .wav).mp3" ; done;
Configurar as opções de histórico da linha de comando em meu .bash_login (ou .bashrc) é realmente útil.A seguir está um conjunto de configurações que uso no meu Macbook Pro.
Definir o seguinte faz com que o bash apague comandos duplicados em seu histórico:
export HISTCONTROL="erasedups:ignoreboth"
Eu também aumentei bastante o tamanho do meu histórico.Por que não?Não parece desacelerar nada nos microprocessadores atuais.
export HISTFILESIZE=500000
export HISTSIZE=100000
Outra coisa que faço é ignorar alguns comandos do meu histórico.Não há necessidade de lembrar o comando de saída.
export HISTIGNORE="&:[ ]*:exit"
Você definitivamente deseja definir histappend.Caso contrário, o bash substituirá seu histórico quando você sair.
shopt -s histappend
Outra opção que uso é o cmdhist.Isso permite salvar comandos multilinhas no histórico como um comando.
shopt -s cmdhist
Finalmente, no Mac OS X (se você não estiver usando o modo vi), você desejará redefinir <CTRL>-S para parar a rolagem.Isso evita que o bash seja capaz de interpretá-lo como pesquisa direta.
stty stop ""
Outras dicas
Renomear/mover arquivos com sufixos rapidamente:
cp /home/foo/realllylongname.cpp{,-old}
Isso se expande para:
cp /home/foo/realllylongname.cpp /home/foo/realllylongname.cpp-old
cd -
É o equivalente em linha de comando do botão Voltar (leva você ao diretório anterior em que estava).
Outro favorito:
!!
Repete seu último comando.Mais útil no formato:
sudo !!
Meu favorito é '^string^string2' que pega o último comando, substitui string por string2 e o executa
$ ehco foo bar baz
bash: ehco: command not found
$ ^ehco^echo
foo bar baz
renomear
Exemplo:
$ ls
this_has_text_to_find_1.txt
this_has_text_to_find_2.txt
this_has_text_to_find_3.txt
this_has_text_to_find_4.txt
$ rename 's/text_to_find/been_renamed/' *.txt
$ ls
this_has_been_renamed_1.txt
this_has_been_renamed_2.txt
this_has_been_renamed_3.txt
this_has_been_renamed_4.txt
Tão útil
sou fã do !$
, !^
e !*
expandos, retornando, da linha de comando enviada mais recentemente:o último item, o primeiro item sem comando e todos os itens sem comando.A saber (observe que o shell imprime o comando primeiro):
$ echo foo bar baz
foo bar baz
$ echo bang-dollar: !$ bang-hat: !^ bang-star: !*
echo bang-dollar: baz bang-hat: foo bang-star: foo bar baz
bang-dollar: baz bang-hat: foo bang-star: foo bar baz
Isso é útil quando você, digamos ls filea fileb
, e deseja editar um deles: vi !$
ou ambos: vimdiff !*
.Também pode ser generalizado para “o n
o argumento" assim:
$ echo foo bar baz
$ echo !:2
echo bar
bar
Finalmente, com nomes de caminhos, você pode obter partes do caminho anexando :h
e :t
para qualquer um dos expandos acima:
$ ls /usr/bin/id
/usr/bin/id
$ echo Head: !$:h Tail: !$:t
echo Head: /usr/bin Tail: id
Head: /usr/bin Tail: id
Como listar apenas subdiretórios no atual?
ls -d */
É um truque simples, mas você não saberia quanto tempo eu precisei para encontrá-lo!
ESC.
Insere os últimos argumentos do seu último comando bash.É mais útil do que você pensa.
cp file /to/some/long/path
cd ESC.
Certamente você pode "diff file1.txt file2.txt
", mas o Bash suporta substituição de processo, o que permite que você diff
a saída de comandos.
Por exemplo, digamos que eu queira ter certeza de que meu script me dará o resultado esperado.Posso simplesmente agrupar meu script em <( ) e alimentá-lo diff
para obter um teste de unidade rápido e sujo:
$ cat myscript.sh
#!/bin/sh
echo -e "one\nthree"
$
$ ./myscript.sh
one
three
$
$ cat expected_output.txt
one
two
three
$
$ diff <(./myscript.sh) expected_output.txt
1a2
> two
$
Como outro exemplo, digamos que eu queira verificar se dois servidores possuem a mesma lista de RPMs instalados.Em vez de enviar sshing para cada servidor, gravar cada lista de RPMs em arquivos separados e fazer um diff
nesses arquivos, posso simplesmente fazer o diff
da minha estação de trabalho:
$ diff <(ssh server1 'rpm -qa | sort') <(ssh server2 'rpm -qa | sort')
241c240
< kernel-2.6.18-92.1.6.el5
---
> kernel-2.6.18-92.el5
317d315
< libsmi-0.4.5-2.el5
727,728d724
< wireshark-0.99.7-1.el5
< wireshark-gnome-0.99.7-1.el5
$
Existem mais exemplos no guia avançado de scripts em http://tldp.org/LDP/abs/html/process-sub.html.
Meu comando favorito é "ls -thor"
Ele convoca o poder dos deuses para listar os arquivos modificados mais recentemente em um formato convenientemente legível.
É mais uma novidade, mas é inteligente...
Os 10 principais comandos usados:
$ history | awk '{print $2}' | awk 'BEGIN {FS="|"}{print $1}' | sort | uniq -c | sort -nr | head
Exemplo de saída:
242 git
83 rake
43 cd
33 ss
24 ls
15 rsg
11 cap
10 dig
9 ping
3 vi
^R pesquisa reversa.Pressione ^R, digite um fragmento de um comando anterior que deseja corresponder e pressione ^R até encontrar o que deseja.Assim não preciso me lembrar de comandos usados recentemente que ainda estão em meu histórico.Não exclusivamente bash, mas também:^E para final de linha, ^A para início de linha, ^U e ^K para excluir antes e depois do cursor, respectivamente.
Muitas vezes tenho aliases para vi, ls, etc.mas às vezes você quer escapar do alias.Basta adicionar uma barra invertida ao comando na frente:
Por exemplo:
$ alias vi=vim
$ # To escape the alias for vi:
$ \vi # This doesn't open VIM
Legal, não é?
Aqui estão alguns ajustes de configuração:
~/.inputrc
:
"\C-[[A": history-search-backward
"\C-[[B": history-search-forward
Isso funciona da mesma forma que ^R
mas usando as teclas de seta.Isso significa que posso digitar (por exemplo) cd /media/
então aperte a seta para cima para ir para a última coisa que eu cd
gostaria de entrar no /media/
pasta.
(Eu uso o Gnome Terminal, talvez seja necessário alterar os códigos de escape para outros emuladores de terminal.)
A conclusão do Bash também é incrivelmente útil, mas é uma adição muito mais sutil.Em ~/.bashrc
:
if [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
Isso permitirá o preenchimento de guias por programa (por exemplo,tentando completar a tabulação quando a linha de comando começa com evince
mostrará apenas os arquivos que o evince pode abrir e também completará as opções de linha de comando).
Funciona bem com isso também em ~/.inputrc
:
set completion-ignore-case on
set show-all-if-ambiguous on
set show-all-if-unmodified on
Eu uso muito o seguinte:
O :p
modificador para imprimir um resultado histórico.Por exemplo.
!!:p
Irá imprimir o último comando para que você possa verificar se está correto antes de executá-lo novamente.Basta entrar !!
para executá-lo.
Na mesma linha:
!?foo?:p
Irá pesquisar em seu histórico o comando mais recente que continha a string 'foo' e imprimi-lo.
Se você não precisa imprimir,
!?foo
faz a pesquisa e a executa imediatamente.
Eu tenho uma arma secreta: concha-fu.
São milhares de dicas inteligentes, truques legais e receitas eficientes que na maioria das vezes cabem em uma única linha.
Um que eu adoro (mas trapaceio um pouco porque uso o fato de que o Python está instalado na maioria dos sistemas Unix agora):
alias webshare='python -m SimpleHTTPServer'
Agora toda vez que você digitar “webshare”, o diretório atual estará disponível através da porta 8000.Muito bom quando você deseja compartilhar arquivos com amigos em uma rede local sem chave USB ou diretório remoto.Streaming de vídeo e música também funcionará.
E, claro, a clássica bomba fork que é completamente inútil, mas ainda assim muito divertida:
$ :(){ :|:& };:
Não tente isso em um servidor de produção ...
Você pode usar o comando watch em conjunto com outro comando para procurar alterações.Um exemplo disso foi quando eu estava testando meu roteador e queria obter números atualizados sobre coisas como relação sinal-ruído, etc.
watch --interval=10 lynx -dump http://dslrouter/stats.html
type -a PROG
Para encontrar todos os lugares onde o Prog está disponível, geralmente em algum lugar em ~/bin, em vez de um em/usr/bin/prog que poderia ser esperado.
Eu gosto de construir comandos com eco e canalize-os para a casca:
$ find dir -name \*~ | xargs echo rm
...
$ find dir -name \*~ | xargs echo rm | ksh -s
Por que?Porque me permite ver o que vai ser feito antes de fazê-lo.Dessa forma, se eu tiver um erro horrível (como remover meu diretório inicial), posso detectá-lo antes que aconteça.Obviamente, isto é mais importante para ações destrutivas ou irrevogáveis.
Ao baixar um arquivo grande, costumo fazer:
while ls -la <filename>; do sleep 5; done
E então apenas ctrl+c quando terminar (ou se ls
retorna diferente de zero).É semelhante ao watch
programa, mas ele usa o shell, então funciona em plataformas sem watch
.
Outra ferramenta útil é o netcat, ou nc
.Se você fizer:
nc -l -p 9100 > printjob.prn
Então você pode configurar uma impressora em outro computador, mas em vez disso usar o endereço IP do computador que executa o netcat.Quando o trabalho de impressão é enviado, ele é recebido pelo computador que executa o netcat e despejado no printjob.prn
.
pushd
e popd
quase sempre é útil
Uma maneira preferida de navegar quando estou usando vários diretórios em locais amplamente separados em uma hierarquia de árvore é usar acf_func.sh (listado abaixo).Uma vez definido, você pode fazer
cd --
para ver uma lista de diretórios recentes, com um menu numérico
disco-2
para ir para o segundo diretório mais recente.
Muito fácil de usar, muito prático.
Aqui está o código:
# do ". acd_func.sh"
# acd_func 1.0.5, 10-nov-2004
# petar marinov, http:/geocities.com/h2428, this is public domain
cd_func ()
{
local x2 the_new_dir adir index
local -i cnt
if [[ $1 == "--" ]]; then
dirs -v
return 0
fi
the_new_dir=$1
[[ -z $1 ]] && the_new_dir=$HOME
if [[ ${the_new_dir:0:1} == '-' ]]; then
#
# Extract dir N from dirs
index=${the_new_dir:1}
[[ -z $index ]] && index=1
adir=$(dirs +$index)
[[ -z $adir ]] && return 1
the_new_dir=$adir
fi
#
# '~' has to be substituted by ${HOME}
[[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"
#
# Now change to the new dir and add to the top of the stack
pushd "${the_new_dir}" > /dev/null
[[ $? -ne 0 ]] && return 1
the_new_dir=$(pwd)
#
# Trim down everything beyond 11th entry
popd -n +11 2>/dev/null 1>/dev/null
#
# Remove any other occurence of this dir, skipping the top of the stack
for ((cnt=1; cnt <= 10; cnt++)); do
x2=$(dirs +${cnt} 2>/dev/null)
[[ $? -ne 0 ]] && return 0
[[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
if [[ "${x2}" == "${the_new_dir}" ]]; then
popd -n +$cnt 2>/dev/null 1>/dev/null
cnt=cnt-1
fi
done
return 0
}
alias cd=cd_func
if [[ $BASH_VERSION > "2.05a" ]]; then
# ctrl+w shows the menu
bind -x "\"\C-w\":cd_func -- ;"
fi
Expanda linhas complicadas antes de acertar o temido enter
- Alt.+Ctrl+e — linha de expansão de shell (pode ser necessário usar Esc, Ctrl+e no seu teclado)
- Ctrl+_ — desfazer
- Ctrl+x, * — glob-expandir-palavra
$ echo !$ !-2^ *
Alt.+Ctrl+e
$ echo aword someotherword *
Ctrl+_
$ echo !$ !-2^ *
Ctrl+x, *
$ echo !$ !-2^ LOG Makefile bar.c foo.h
etc.
Sempre fui parcial em:
ctrl-E # move cursor to end of line
ctrl-A # move cursor to beginning of line
Eu também uso shopt -s cdable_vars
, então você pode criar variáveis bash para diretórios comuns.Então, para a árvore de origem da minha empresa, crio um monte de variáveis como:
export Dcentmain="/var/localdata/p4ws/centaur/main/apps/core"
então posso mudar para esse diretório cd Dcentmain
.
pbcopy
Isso copia para a área de transferência do sistema Mac.Você pode canalizar comandos para ele... tente:
pwd | pbcopy
$ touch {1,2}.txt
$ ls [12].txt
1.txt 2.txt
$ rm !:1
rm [12].txt
$ history | tail -10
...
10007 touch {1,2}.txt
...
$ !10007
touch {1,2}.txt
$ for f in *.txt; do mv $f ${f/txt/doc}; done
Usar 'set -o vi' na linha de comando, ou melhor, em .bashrc, coloca você no modo de edição vi na linha de comando.Você começa no modo 'inserir' para poder digitar e retroceder normalmente, mas se cometer um erro 'grande', pode pressionar a tecla esc e usar 'b' e 'f' para se mover como faz no vi.cw para alterar uma palavra.Particularmente útil depois de você abrir um comando de histórico que deseja alterar.
Semelhante a muitos acima, meu favorito atual é o pressionamento de tecla [alt].(teclas Alt e "." juntas) é o mesmo que $!(Insere o último argumento do comando anterior), exceto que é imediato e mais fácil de digitar.(Simplesmente não pode ser usado em scripts)
por exemplo:
mkdir -p /tmp/test/blah/oops/something
cd [alt].
Seque vários comandos juntos usando o && comando:
./run.sh && tail -f log.txt
ou
kill -9 1111 && ./start.sh