Wie kann ich eines der Ergebnisse von `locate` auswählen und es mit einer angegebenen Anwendung öffnen lassen?

Wie kann ich eines der Ergebnisse von `locate` auswählen und es mit einer angegebenen Anwendung öffnen lassen?

Ich habe ein Bash-Skript namens findme, das wie folgt codiert ist:

#!/bin/bash
locate -Abi '*\.'$1 $2 | grep --color=always -ni $2 | less -R

Es sucht für mich nach allen Dateien mit einer bestimmten Dateierweiterung (erstes Argument, das dem Skript übergeben wird), die ein Muster (das nächste übergebene Argument) im Dateinamen haben.
Wenn ich Folgendes ausführe:

user@machine$ findme pdf classifi

pdfEs wird nach allen Dateien gesucht, die classifiden Dateinamen enthalten. Ich erhalte also möglicherweise das folgende Ergebnis.

1:/home/Benutzer/Dropbox/SharedWithFriends/math/klassifizierenkationen2000.pdf
2:/home/Benutzer/Dropbox/SharedWithFriends/math/klassifizierenkationen2010.pdf

Die Frage ist: „Können Sie mir einen Bash-Skriptcode geben, der mich nach der Anzeige der Ergebnisse nach einer Nummer und einem Viewer fragt, um meinen nächsten Job zu automatisieren?“

Ich möchte beispielsweise, dass ich Folgendes eingebe:

> 2 evince

Das Skript wird evincefür das 22. Element des Suchergebnisses ausgeführt.dh, wenn es das ist, was ich im vorherigen Suchergebnis eingegeben habe, wird Folgendes ausgeführt:

evince /home/user/Dropbox/SharedWithFriends/math/classifications2010.pdf

Antwort1

Hier ist eine Variante Ihrer findmeFunktion, die die Ergebnisse abruft. Anstatt grepsie jedoch zu nummerieren oder lesszu paginieren, listet sie sie aus einem internen Array auf und fordert Sie dann zur Auswahl Ihres Elements und Programms auf.

#!/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]}"

Ich habe Ihrem Originalskript einige Anführungszeichen hinzugefügt, um mit Leerzeichen in Dateinamen oder sogar Grep-Parametern besser umgehen zu können. Ich habe den readarrayAufruf so angepasst, dass die Ergebnisse bei Index 1 statt 0 beginnen, sodass es der Nummerierung von Grep entspricht.

Antwort2

Beachten Sie, dass Ihr findmeSkript einige Probleme aufweist:

  • Fehlende Anführungszeichen um Variablensubstitutionen
  • Die Ausgabe von grep --color=alwayserzeugt Ergebnisse, die nicht in einer Befehlsersetzung verwendet werden können. Sie müssen sie durchgeben less, aber versuchen Sie nicht, sie in einem Skript wiederzuverwenden.
  • grep und locate verwenden unterschiedliche Mustersyntaxen, daher grepfunktioniert die Verwendung zum Färben des zweiten Arguments nicht immer. Die Übergabe -ran locatebewirkt, dass reguläre Ausdrücke verwendet werden, allerdings mit einer Emacs-Syntax, die sich leicht von den von grep unterstützten Syntaxen unterscheidet.

In Bash können Sie verwendenmapfileum einige Zeilen zuverlässig in ein Array zu packen. Kombinieren Sie es mitProzesssubstitutionum die Ausgabe eines Befehls zu verwenden. Drucken Sie dann dieses Array aus und lesen Sie die Eingabe des Benutzers.

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
}

Eine alternative Schnittstelle wäre das Setzen der Positionsparameter. Das ist ein bisschen knifflig, weil man die Positionsparameter nicht von einer Funktion aus ändern kann, aber es gibt eineUmweg, es in Bash zu tunindem Sie ein Pseudonym verwenden und ein Skript als Quelle angeben. Vorsicht beim Zitieren.

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
}

Verwendung:

findrun pdf classifi
evince "$2"

Antwort3

Basierend auf der Lösung von Jeff Schaller. Ich habe eine Lösung gefunden und würde mich über Kommentare freuen, um sie zu verbessern.

#!/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]}"

Dies scheint eine einfache (bis auf die Komplexität der Themen) Antwort zu sein.

Aber es ist nicht gut genug, wenn die Ergebnisse mehr als eine bestimmte Zahl sind! In diesem Fall brauchen wir etwas wie moreoderless

verwandte Informationen