Listen Sie alle Dateien / Binärdateien im aktuellen PATH auf

10

Gibt es eine "einfache" Möglichkeit, einen Befehl im "ls -la" -Stil auszuführen, um alle Dateien / ausführbaren Binärdateien im aktuellen PATH aufzulisten?

(Ich beabsichtige, die Ausgabe in grep weiterzuleiten, um nach Befehlen mit unbekannten Präfixen, aber im Grunde bekannten "Namen" zu suchen. Dies ist der Fall, wenn die automatische Vervollständigung / Tabulation in Bash im Wesentlichen nutzlos ist. Also eine Art "inverse automatische" komplettes Feature "...)

sme
quelle
Können Sie Beispiele nennen? Wie wird es anders sein mit ls -la?
John Siu
"ls -la" / "ls -a" listet nur Dateien in Ihrem aktuellen Verzeichnis (pwd) auf. Ich möchte alle (ausführbaren) Dateien in allen in PATH enthaltenen Verzeichnissen auflisten.
sme

Antworten:

19
compgen -c # will list all the commands you could run.
compgen -a # will list all the aliases you could run.
compgen -b # will list all the built-ins you could run.
compgen -k # will list all the keywords you could run.
compgen -A function # will list all the functions you could run.
compgen -A function -abck # will list all the above in one go. 
Nykakin
quelle
Schön, das ist genau das, wonach ich gesucht habe. Es enthält sogar ausführbare Binärdateien im aktuellen Verzeichnis. Vielen Dank.
sme
Funktioniert gut ... in Bash.
Emanuel Berg
Gibt es eine Möglichkeit, den Pfad jedes dieser Elemente aufzulisten, ohne dies zu tun which $(compgen -A function -abck)?
h3rrmiller
Ich könnte keine bessere Alternative finden.
Nykakin
3

Hier ist eine Funktion, die den Inhalt der Verzeichnisse auflistet $PATH. Wenn Argumente übergeben werden, listet die Funktion nur Befehle auf, deren Name eines der Argumente enthält. Die Argumente werden als Glob-Muster interpretiert.

shopt -s extglob
lspath () {
  local IFS pattern
  IFS='|'
  pattern="*@($*)*"
  IFS=':'
  for d in $PATH; do
    for x in "$d/"$pattern; do
      [ "$x" = "$d/$pattern" ] || echo "${x##*/}"
    done
  done | sort -u
}

Wie viele Dinge ist dies in zsh einfacher.

lspath () {
  (($#)) || set ''
  print -lr -- $^path/*$^@*(N:t) | sort -u
}

Das ^Zeichen in der Parametererweiterung bewirkt, dass der mit dem Array verkettete Text zu jedem Array-Element hinzugefügt wird, z . B. path=(/bin /usr/bin); echo $^path/fooAusdrucke /bin/foo /usr/bin/foo.
/*$^@*sieht aus wie eine Comic-Beleidigung, ist aber tatsächlich das gewöhnliche Zeichen /, der Platzhalter *, der spezielle Parameter $@(das Array der Positionsparameter) mit dem ^Modifikator und wieder *.
(N:t)ist das Glob-Qualifikationsmerkmal N , um eine leere Erweiterung zu erhalten, wenn keine Übereinstimmung vorliegt t , gefolgt vom Verlaufsmodifikator , um nur den Basisnamen ("Schwanz") jeder Übereinstimmung beizubehalten.

Kryptischer, vermeidet den externen Anruf, aber dies ist nur von kosmetischem Interesse:

lspath () {
  (($#)) || set ''
  local names; names=($^path/*$^@*(N:t))
  print -lr -- ${(ou)names}
}

Möglicherweise suchen Sie tatsächlich nach dem aproposBefehl, der nach Manpages von Befehlen sucht, deren Kurzbeschreibung ein Schlüsselwort enthält. Eine Einschränkung besteht darin, dass nur Befehle gefunden werden, die eine Manpage haben.

Gilles 'SO - hör auf böse zu sein'
quelle
In der zsh-Funktion ^scheint die zweite zu keiner Ausgabe für einen Aufruf "keine Argumente" zu führen? Wenn Sie es löschen, können Sie alle auflisten und trotzdem nach einzelnen Schlüsselwörtern suchen (aber nicht nach einer Liste). Das (Non:t)scheint zu sagen, dass Sternchen erweitert werden sollten? Konnte den letzten nicht herausfinden.
Emanuel Berg
@EmanuelBerg Richtig, danke für das Update. Ich habe eine Erklärung für das Leitungsrauschen hinzugefügt.
Gilles 'SO - hör auf böse zu sein'
OK, mal sehen: Wenn es keine Argumente gibt, setzen Sie "sie" auf nichts, denn was war da (wenn es keine gab), war irgendwie irgendwie störend für das, was Sie als nächstes getan haben? Ich habe auch noch nie Kleinbuchstaben gesehen path, aber wenn ich es in der Shell ausführe, ist es zwar $ PATH, aber mit Leerzeichen anstelle von :. Der Rest ist kristallklar :)
Emanuel Berg
@EmanuelBerg Nein: Wenn es keine Argumente gibt, setze ich das Array von Argumenten auf ein Ein-Element-Array, das die leere Zeichenfolge enthält. Auf diese Weise bedeutet kein Argument, dass jeder Name, der die leere Zeichenfolge enthält, übereinstimmt, dh jeder Name stimmt überein. $pathist eine zsh-Funktion: Es ist ein gebundener Parameter , ein Array, das automatisch aktualisiert wird, wenn PATHes aktualisiert wird, und umgekehrt.
Gilles 'SO - hör auf böse zu sein'
Aha, jetzt verstehe ich! Wow, das war unorthodox!
Emanuel Berg
1
function findinpath () { 
   OLDIFS="$IFS" ; 
   IFS="$(printf ':\t\n')" ; 
   for regexp in "$@" ; do 
      for adir in $PATH ; do 
         find "$adir" -perm -111 -a ! -type d -ls 2>/dev/null | grep -i "/[^/]*$regexp"
      done ; 
   done ; 
   IFS="$OLDIFS" ; 
}

Der Fund stimmt nur mit folgenden Punkten überein: Mindestens ein "x" -Bit (ausführbar) gesetzt, und das ist kein Verzeichnis.

und verwenden Sie es mit einer Liste von Regexp zu finden:

findinpath awk sed '\.sh$'
Olivier Dulac
quelle
regulärer Ausdruck "." wird Ihnen alles zeigen
Olivier Dulac
Mit dem regulären IFS können Sie doppelte Einträge in Ihrem $ PATH finden mit:echo $PATH | tr ':' '\n' | sort | uniq -d
Olivier Dulac
1
Ich habe den Code für alle Antworten ausprobiert und dies ist der einzige, der mir tatsächlich das gab, wonach ich gesucht habe (vollständige Pfade zu jeder Instanz eines bestimmten Befehls im PATH).
Chris Seite
Ich bin froh, dass es geholfen hat :)
Olivier Dulac
1
for i in $(echo $PATH | sed -e 's/\:/\ /g'); do find "$i" -perm +rwx -exec echo {} \; 2> /dev/null; done

Zuerst wiederholen wir $PATHin sed und ersetzen ":" durch "".

Dann suchen wir nach jedem dieser Dinge, um Dateien mit rwx zu finden und sie wiederzugeben.

2> /dev/nullwird also findkeine Fehler drucken

h3rrmiller
quelle
3
Sie benötigen ein -maxdepth 1und -type fin Ihrem Fund, sonst finden Sie Unterverzeichnisse und deren Dateien (was bei der PATH-Suche nicht der Fall ist). Außerdem ist Ihr Erlaubnis-Test seltsam - sollte nur für +x, würde ich denken?
Derobert
Dies behandelt die Randfälle nicht, wenn ein gültiger leerer Eintrag mit '.' Entspricht, z. B. :/binoder /bin::/usr/bin. Versuchen Sie s/::/:.:/;s/^:/.:/;s/:$/:./, dem sedBefehl etwas hinzuzufügen .
Arcege
findKann tatsächlich mehr Pfade durchsuchen, so dass Sie es ohne die Schleife tun können: find $(echo $PATH | sed -e 's/\:/\ /g') -perm +rwx …Natürlich werden Verzeichnisnamen, die Leerzeichen enthalten, es durcheinander bringen, aber der schleifenbasierte hat trotzdem das gleiche Problem.
Manatwork
@manatwork du hast recht. Ich habe gerade Zitate hinzugefügt, um dieses Problem zu lösen
h3rrmiller
Entschuldigung, das löst nichts. Das Problem besteht darin, die Doppelpunkte durch Leerzeichen zu ersetzen, um die Wortteilung zu ermöglichen. Also transformierst du "/ foo bar: / fiz baz" in "/ foo bar / fiz baz" und gibst das an weiter for. So forwird eine Liste von 4 Wörtern durchlaufen. Um die Wortteilung besser zu manipulieren, stellen Sie die Einstellungen IFSentsprechend Ihren Anforderungen ein : IFS=':'; find $PATH -perm +rwx ….
Manatwork