
Tengo un script bash llamado findme
, que está codificado de la siguiente manera:
#!/bin/bash
locate -Abi '*\.'$1 $2 | grep --color=always -ni $2 | less -R
Me busca todos los archivos con una extensión de archivo especificada (el primer argumento proporcionado al script) que tiene un patrón (el siguiente argumento proporcionado) en su nombre de archivo.
Si ejecuto lo siguiente:
user@machine$ findme pdf classifi
Buscará todos pdf
los archivos que contengan classifi
su nombre de archivo. Entonces puedo obtener algo como el siguiente resultado.
1:/home/usuario/Dropbox/SharedWithFriends/matemáticas/clasificarcationes2000.pdf
2:/home/user/Dropbox/SharedWithFriends/math/clasificarcationes2010.pdf
La pregunta es: "¿Puedes darme un código de script bash en el que luego de mostrar los resultados me solicite un número y un visor, para automatizar mi próximo trabajo?"
por ejemplo me gustaría, si ingreso:
> 2 evince
el script se ejecuta evince
en el 2
segundo elemento del resultado de la búsqueda,es decir, si esto es lo que ingresé en el resultado de búsqueda anterior, se ejecuta:
evince /home/user/Dropbox/SharedWithFriends/math/classifications2010.pdf
Respuesta1
Aquí hay una variación de su findme
función que muestra los resultados, pero en lugar de grep
numerarlos o less
paginarlos, los enumera desde una matriz interna y luego le solicita su elemento y programa elegido.
#!/usr/bin/env bash
readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2" | grep --color=always -i "$2")
for((i=1; i <= ${#results[*]}; i++))
do
printf "%d: %s\n" $i "${results[i]}"
done
read -p "> " item program
$program "${results[item]}"
Agregué algunas citas a su script original para manejar mejor los espacios en los nombres de archivos, o incluso los parámetros grep. Ajusté la readarray
llamada para que los resultados comiencen en el índice 1 en lugar de 0, para que corresponda a la numeración de grep.
Respuesta2
Tenga en cuenta que su findme
secuencia de comandos tiene algunos problemas:
- Faltan comillas dobles alrededor de sustituciones de variables
- La salida de
grep --color=always
produce resultados que no se pueden utilizar en una sustitución de comando. Lo necesita para pasarless
, pero no intente reutilizarlo en un script. - grep y localizar usan una sintaxis de patrón diferente, por lo que usarlo
grep
para colorear el segundo argumento no siempre funcionará. Pasar-r
alocate
hace que use expresiones regulares, pero con la sintaxis de Emacs que es ligeramente diferente de las sintaxis que admite grep.
En bash, puedes usarmapfile
para introducir de forma fiable algunas líneas en una matriz. Combínalo consustitución de procesospara utilizar la salida de un comando. Luego imprima esa matriz y lea la entrada del usuario.
findrun () {
mapfile search_hits <(locate -Abir ".*\.$1" "$2")
print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2"
if read -a cmd; then
set -- "${cmd[@]}"
set -- "$@" "${search_hits[$1]}"
shift
"$@"
fi
}
Una interfaz alternativa sería establecer los parámetros posicionales. Es un poco complicado, porque no puedes cambiar los parámetros posicionales de una función, pero hay unaforma indirecta de hacerlo en bashutilizando un alias y obteniendo un script. Cuidado con las citas.
alias findrun='. <(echo findrun_prepare \"\$@\"; echo set -- "\"\${search_hits[@]}\"")'
findrun_prepare () {
mapfile search_hits <(locate -Abir ".*\.$1" "$2")
print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2" >&2
}
Uso:
findrun pdf classifi
evince "$2"
Respuesta3
Basado en la solución dada por Jeff Schaller. Encontré una solución, me alegraría recibir sus comentarios para mejorarla.
#!/bin/bash
readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2")
for((i=1; i <= ${#results[*]}; i++))
do
printf "%d: %s" $i "${results[i]}" | grep --color=always -i "$2"
done
read -p "> " item program
$program "${results[item]}"
Esto parece una respuesta simple (hasta la complejidad de los temas).
¡Pero no es suficiente si los resultados superan un determinado número! En ese caso necesitamos algo como more
oless