Forma rápida de abrir los resultados de `find` o` locate`

Cuando ejecuto find o locate , los files coincidentes rellenarán stdout, un file por línea. El próximo paso es a menudo que quiero abrir uno de estos files. Esto sería más rápido y más eficiente si no tuviera que escribir la ruta completa del file, sino que simplemente podría interactuar con los resultados de búsqueda de alguna manera. ¿Cuál es la forma más rápida de abrir un file mostrado en los resultados de búsqueda?

Soluciones como las que se dan en Abrir un resultado de `localizar` con` vi` , ¿Cómo `ubicar` varios files y abrirlos en vim? y ¿cómo puedo actuar sobre los resultados del command "localizar"? requieren escribir un segundo command bastante largo, que no es tan rápido como me gustaría.

En su lugar, ¿hay alguna manera de, por ejemplo, asignar automáticamente cada file del resultado de búsqueda a un nombre de variable numérica (s1 – sn), de modo que para abrir el primer resultado simplemente escriba vi $s1 ? ¿O es una mejor solución a este problema usar un buscador difuso como fzf o fasd ?

He tenido esto en mi ~/.screenrc por un time:

 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 

Básicamente, al escribir ¬ 1 desde la pantalla, inserta la primera línea sobre el cursor, ¬ 2 la segunda línea y así sucesivamente.

En mis ~/.Xdefaults , también tengo:

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

Lo que permite que xterm complete (con Alt + / ) en lo que hay en la pantalla (mirando hacia atrás desde la position del cursor).

Con zsh , cuando se usa dentro de la screen , puedes hacer:

 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 enlazar Alt + C a ese widget que almacena las líneas sobre el cursor en el buffer de corte y el kill ring (lo que pegas con Ctrl + Y y ciclo con Alt + Y en modo emacs ). (lo anterior supone que la screen se inició desde su directory de inicio).

Si el text insertado necesita ser citado (porque contiene espacios u otros caracteres de shell especiales, por ejemplo), puede escribir Alt + " para que zsh cite.

Como ejemplo, acaba de ejecutar:

 $ 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 

Y desea abrir vim en ese sudo ChangeLog arriba. Con el primer enfoque escribirías:

 vim ¬9 

Con el segundo enfoque:

  vim / us Alt + / 

Y repite Alt + / hasta que llegues al logging de cambios.

Con el tercer enfoque:

  vim Alt + C Ctrl + Y Alt + Y 

Y repite Alt + Y hasta que llegues al logging de cambios.

El último enfoque se puede usar para su consulta $s1 .

En lugar de almacenar en la matriz de killring , almacenar en una matriz (como $s ) y usar $s[1] para la primera línea, $s[2] para la segunda …

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

Que Alt + C almacena las líneas sobre el cursor en la matriz s .

En cualquier caso, lo que estamos recuperando es lo que se muestra en la pantalla, que no es necesariamente lo mismo que la última salida del command. Por ejemplo printf 'a\bc \n' genera 5 bytes a , BS, c , SPC y LF, pero muestra solo una c .

Si puedes soportar la fealdad de los arreglos Bash, podrías hacer algo como

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

o

 mapfile res < <(locate <pattern>) 

Esto saveá sus líneas en una matriz res .

Luego puede ver las coincidencias e iterar a través de ellas:

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

PD

Sin embargo, solo uso el mouse para seleccionar la línea que necesito. O simplemente hazlo

 $ editor `locate <pattern>` 

si sé que no hay muchos resultados o personajes "extravagantes".

Con bash :

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

Con Vim:

 !!locate fubar 

– luego vaya al file que desea y presione g f . Ver también :h gf y :h 'isfname' .

Otra forma con Vim: ver :h :find . Con las versiones recientes de Vim, vea :h :filter .

Otra forma más con Vim: usa el plugin Unite . O bien, para operaciones de tipo grep , use el complemento CtrlSF . Hay, por supuesto, muchas otras forms.

Un método viene a la mente. Puede usar el editor de pantalla completa especificado por 'EDITOR' en su entorno de shell. El editor se inicia presionando ^X^E (ctrl-x, ctrl-e). Desde dentro del editor (como vim) podrías ejecutar:

 :r!find / 

Los resultados de esto se importarían, puede recortar la salida a lo que desee, cuando escriba y salga, el contenido se ejecutará como un command, como si lo hubiera ingresado en el indicador del shell.

Combiné las ideas de las respuestas de Sato Katsura y Stéphane Chazelas en un guión, que tiene un alias para sr (para "Seleccionar resultado"). Se puede invocar después de un command que envía routes línea por línea a stdout. Por ejemplo

 $ 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 #? 

La secuencia de commands entonces espera que escriba un número y presione enter, después de lo cual abre ese elemento en el progtwig especificado como el primer argumento (en este caso zathura, para el cual he definido la abreviatura zh en la secuencia de commands). Todavía tengo que probar esto extensamente, pero está haciendo todo lo que quiero en este momento.

Mi solución actual requiere tmux , ya que puede acceder a la salida del último command sin volver a ejecutarlo (copyndo desde el terminal). Existen soluciones similares para la screen como se muestra en la respuesta de Stéphane Chazelas. Si no usa ninguno de estos, simplemente podría get el último command del historial y luego evaluarlo de nuevo en la instrucción de select . A continuación se muestra el guión completo.

 #!/usr/bin/env bash # Enumerate stdout from the previous search command line by line. # Enable opening a file by passing the desinetworking 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"