¿Cómo puedo elegir uno de los resultados de "localizar" y permitir que se abra con una aplicación específica?

¿Cómo puedo elegir uno de los resultados de "localizar" y permitir que se abra con una aplicación específica?

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 pdflos archivos que contengan classifisu 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 evinceen el 2segundo 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 findmefunción que muestra los resultados, pero en lugar de grepnumerarlos o lesspaginarlos, 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 readarrayllamada 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 findmesecuencia de comandos tiene algunos problemas:

  • Faltan comillas dobles alrededor de sustituciones de variables
  • La salida de grep --color=alwaysproduce resultados que no se pueden utilizar en una sustitución de comando. Lo necesita para pasar less, pero no intente reutilizarlo en un script.
  • grep y localizar usan una sintaxis de patrón diferente, por lo que usarlo greppara colorear el segundo argumento no siempre funcionará. Pasar -ra locatehace que use expresiones regulares, pero con la sintaxis de Emacs que es ligeramente diferente de las sintaxis que admite grep.

En bash, puedes usarmapfilepara 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 moreoless

información relacionada