Maneira rápida de abrir resultados de 'find' ou 'locate'

2

Quando executo find ou locate , os arquivos correspondentes preencherão o stdout, um arquivo por linha. O próximo passo é frequentemente que eu quero abrir um desses arquivos. Isso seria mais rápido e eficiente se eu não precisasse digitar todo o caminho do arquivo, mas simplesmente pudesse interagir com os resultados da pesquisa de alguma forma. Qual é o caminho mais rápido para abrir um arquivo exibido nos resultados da pesquisa?

Soluções como as apresentadas em Abra o resultado de 'locate' com 'vi' , Como 'localizar' vários arquivos e abri-los no vim? , e Como posso agir sobre os resultados do comando" locate "? requer a digitação de um segundo comando bastante longo, que não é tão rápido quanto Eu gostaria.

Em vez disso, existe uma maneira de, por exemplo, atribuir automaticamente cada arquivo do resultado da pesquisa a um nome de variável numérica (s1 - sn), para que, para abrir o primeiro resultado, eu simplesmente digite vi $s1 ? Ou é uma solução melhor para esse problema usar um localizador difuso como fzf ou fasd ?

    
por joelostblom 28.02.2017 / 20:22

5 respostas

5

Eu tive isso no meu ~/.screenrc por um tempo:

bind -c pasteline 1 eval copy 'stuff "-Y"' 'paste .'
bind -c pasteline 2 eval copy 'stuff "2-Y"' 'paste .'
bind -c pasteline 3 eval copy 'stuff "3-Y"' 'paste .'
bind -c pasteline 4 eval copy 'stuff "4-Y"' 'paste .'
bind -c pasteline 5 eval copy 'stuff "5-Y"' 'paste .'
bind -c pasteline 6 eval copy 'stuff "6-Y"' 'paste .'
bind -c pasteline 7 eval copy 'stuff "7-Y"' 'paste .'
bind -c pasteline 8 eval copy 'stuff "8-Y"' 'paste .'
bind -c pasteline 9 eval copy 'stuff "9-Y"' 'paste .'
bindkey ¬ command -c pasteline

Basicamente, digitando ¬ 1 dentro da tela, insere a primeira linha acima do cursor, ¬ 2 a segunda linha e assim por diante.

No meu ~/.Xdefaults , também tenho:

XTerm.VT100.translations:             #override\
    Meta <KeyPress> /: dabbrev-expand()

Que permite que xterm complete (com Alt + / ) o que está na tela (olhando para trás a partir da posição do cursor).

Com zsh , quando usado em screen , você poderia fazer:

copy-screen() {
  screen -X eval copy 'stuff "-$ H\r"' 'writebuf .lastoutput'
  killring=(${(Oaf)"$(<~/.lastoutput)"})
  CUTBUFFER=$killring[1]
  killring[1]=()
}
zle -N copy-screen
bindkey '\ec' copy-screen

para ligar Alt + C ao widget que armazena as linhas acima do cursor no buffer de corte e no anel kill (o que você cola com Ctrl + Y e ciclo através de Alt + Y no modo emacs ). (o acima assume que screen foi iniciado a partir do seu diretório pessoal).

Se o texto inserido precisar ser citado (porque contém espaços ou outros caracteres especiais de shell, por exemplo), você pode digitar Alt + " para zsh para citá-lo.

Como exemplo, você acabou de executar:

$ find /usr/local -size +1M
/usr/local/lib/liblzma.a
/usr/local/share/doc/sudo/ChangeLog
/usr/local/share/perl/5.18.2/Unicode/Unihan/Definition.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/RSKangXi.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/IRG_TSource.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/HanYu.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/RSUnicode.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/IRG_GSource.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/IRGKangXi.db
/usr/local/share/perl/5.18.2/Unicode/Unihan/IRGHanyuDaZidian.db    

E você deseja abrir vim no sudo ChangeLog acima. Com a primeira abordagem, você digitaria:

vim ¬9

Com a segunda abordagem:

vim /usAlt+/

E repita que Alt + / até chegar ao changelog.

Com a terceira abordagem:

vim Alt+CCtrl+YAlt+Y

E repita que Alt + Y até chegar ao changelog.

A última abordagem pode ser usada para sua consulta $s1 .

Em vez de armazenar na matriz killring , armazene em uma matriz (como $s ) e use $s[1] para a primeira linha, $s[2] para a segunda ...

copy-screen() {
  screen -X eval copy 'stuff "-$ H\r"' 'writebuf .lastoutput'
  s=(${(Oaf)"$(<~/.lastoutput)"})
}
zle -N copy-screen
bindkey '\ec' copy-screen

Aquele Alt + C armazena as linhas acima do cursor na matriz s .

Em qualquer caso, o que estamos recuperando é o que é exibido na tela, o que não é necessariamente o mesmo que o resultado do último comando. Por exemplo, printf 'a\bc \n' produz 5 bytes a , BS, c , SPC e LF, mas exibe apenas c .

    
por 01.03.2017 / 23:07
4

Se você pode suportar a fealdade dos arrays Bash, você pode fazer algo como

mapfile res < <(find -name <pattern>)

ou

mapfile res < <(locate <pattern>)

Isso salvará suas linhas em uma matriz res .

Depois, você pode ver as correspondências e iterar por elas:

$ echo "${res[@]}" # lists all matches
$ editor ${res[2]} # opens the third match

PS

Eu só uso o mouse para selecionar a linha que eu preciso, no entanto. Ou apenas faça

$ editor 'locate <pattern>'

se eu souber que não há muitos resultados ou caracteres "extravagantes".

    
por 28.02.2017 / 23:09
4

com bash :

IFS=$'\n' select fname in $(locate fubar); do
    if [ "$fname" ]; then
        vim "$fname"
        break
    fi
done

Com o Vim:

!!locate fubar

- depois vá para o arquivo desejado e pressione g f . Veja também :h gf e :h 'isfname' .

Outra maneira com o Vim: veja :h :find . Com versões recentes do Vim, consulte :h :filter .

Ainda uma outra maneira com o Vim: use o plugin Unite . Ou, para operações com grep , use o plug-in CtrlSF . Existem, claro, muitas outras maneiras.

    
por 28.02.2017 / 20:38
0

Um método vem à mente. Você poderia usar o editor de tela inteira especificado por 'EDITOR' no seu ambiente shell. O editor é iniciado pressionando ^X^E (ctrl-x, ctrl-e). De dentro do editor (como o vim) você pode executar:

:r!find /

Os resultados disto seriam importados, você pode então ajustar a saída para o que você deseja, quando você escreve e sai, o conteúdo seria executado como um comando, como se você tivesse digitado no prompt do shell.

    
por 28.02.2017 / 21:49
0

Combinei as idéias das respostas de Sato Katsura e Stéphane Chazelas em um script, que é aliado para sr (para "Selecionar resultado"). Ele pode ser chamado após um comando que gera caminhos linha por linha para stdout. Por exemplo

$ locate genomics
/home/user/articles/macaulay_voet_2014_plos_genetics.pdf
/home/user/articles/shmulevich_et_al_2003_comparative_functional_genomics.pdf

$ sr zh
1) /home/user/articles/macaulay_voet_2014_plos_genetics.pdf
2) /home/user/articles/shmulevich_et_al_2003_comparative_functional_genomics.pdf
#? 

O script então espera que eu digite um número e pressione enter, após o qual ele abre esse item no programa especificado como o primeiro argumento (neste caso, zathura, para o qual eu defini a abreviação zh no script ). Eu ainda tenho que testar isso extensivamente, mas está fazendo tudo o que eu quero no momento.

Minha solução atual requer tmux , pois ele pode acessar a saída do último comando sem executá-lo novamente (copiando do terminal). Existem soluções similares para screen como mostrado na resposta de Stéphane Chazelas. Se não usar nenhum desses, pode-se simplesmente obter o último comando do histórico e, em seguida, avaliá-lo novamente na instrução select . Abaixo está o roteiro completo.

#!/usr/bin/env bash

# Enumerate stdout from the previous search command line by line.
# Enable opening a file by passing the desired opening program as an
# argument and then select a number from the output.
# Defaults to using 'xdg-open' when no argument is passed.
# Does only work for stdout that list the full path to a file or relative
# the directory this script is being called from.

# Aliases are not expanded within bash scripts.
# Create a few aliases instead of importing entire alias file.
case $1 in
    '' )
        opener='xdg-open'
        ;;
    'vi' )
        opener='nvim'
        ;;
    'zh' )
        opener='zathura'
        ;;
    * )
        opener=$1
esac

# The default split delimiter in bash is any whitespace. Change this
# to only split on newline in order to account for filenames with spaces.
old_IFS="$IFS"
IFS=$'\n'

# Use tmux to copy the paragraph above. This specific navigation sequence
# only works if each prompt is prefaced with a newline, such as from having
# 'precmd() { print "" }' in '.zshrc'
tmux copy-mode
tmux send-keys 2 { 3 j 0 space } enter
# Results are saved in an array for clarity
search_results+=$(tmux save-buffer -)
select fname in $search_results; do
    $opener "$fname"
    break
done

# Set IFS back to default
IFS="$old_IFS"
    
por 01.03.2017 / 18:35