Listen Sie alle Binärdateien von $ PATH auf

29

Gibt es einen Einzeiler, der alle ausführbaren Dateien von $ PATH in bash auflistet?

jcubic
quelle

Antworten:

38

Dies ist keine Antwort, sondern zeigt binär, einen Befehl, den Sie ausführen könnten

compgen -c

(vorausgesetzt bash)

Andere nützliche Befehle

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.
Rahul Patil
quelle
1
Gut zu wissen, dass dieser Befehl ausgeführt wird, und ich benötige ausführbare Dateien, um ihn ausführen zu können. Vielleicht verwende ich stattdessen diesen Befehl.
jcubic
Beachten Sie, dass es enthält auch builtins, Funktionen, Schlüsselwörter (wie in, {...) und Aliase.
Stéphane Chazelas
Sir, ich habe aktualisiert .. Ich hatte in meinem Entwurf gespeichert, vor langer Zeit fand ich auf dieser Website ..
Rahul Patil
@jcubic, die Shells erledigen das bereits für die Befehlsvervollständigung. Warum von Hand?
Vonbrand
@vonbrand Ich arbeite an der Shell in Javascript / PHP und führe die Shell im nicht interaktiven Modus aus.
JCUBIC
14

Mit zsh:

whence -pm '*'

Oder:

print -rl -- $commands

(Beachten Sie, dass bei Befehlen, die in mehr als einer Komponente von vorkommen $PATH, nur die erste aufgeführt wird.)

Wenn Sie die Befehle ohne die vollständigen Pfade und nach guten Maßen sortiert haben möchten:

print -rl -- ${(ko)commands}

(Das heißt, erhalten Sie die Schlüssel dieses assoziativen Arrays anstelle der Werte).

Stéphane Chazelas
quelle
Ich habe nicht erwähnt, dass ich bash benutze.
JCUBIC
5

In jeder POSIX-Shell, ohne einen externen Befehl zu verwenden (vorausgesetzt, es printfist eine Funktion integriert, auf die nicht zurückgegriffen wird echo), mit Ausnahme der endgültigen Sortierung und unter der Annahme, dass kein ausführbarer Name eine neue Zeile enthält:

{ set -f; IFS=:; for d in $PATH; do set +f; [ -n "$d" ] || d=.; for f in "$d"/.[!.]* "$d"/..?* "$d"/*; do [ -f "$f" ] && [ -x "$f" ] && printf '%s\n' "${x##*/}"; done; done; } | sort

Wenn Sie keine leere Komponente in $PATH( .stattdessen verwenden) oder Komponenten haben, die mit beginnen -, oder Platzhalterzeichen \[?*in PATH-Komponenten oder ausführbaren Namen und keine ausführbaren Dateien, die mit beginnen ., können Sie dies folgendermaßen vereinfachen:

{ IFS=:; for d in $PATH; do for f in $d/*; do [ -f $f ] && [ -x $f ] && echo ${x##*/}; done; done; } | sort

Verwendung von POSIX findund sed:

{ IFS=:; set -f; find -H $PATH -prune -type f -perm -100 -print; } | sed 's!.*/!!' | sort

Wenn Sie bereit sind, die seltene nicht ausführbare Datei oder die nicht reguläre Datei im Pfad aufzulisten, gibt es einen viel einfacheren Weg:

{ IFS=:; ls -H $PATH; } | sort

Dadurch werden Punktdateien übersprungen. Wenn Sie sie brauchen, fügen Sie die -AFlagge hinzu, lswenn Sie sie haben oder wenn Sie sich an POSIX halten möchten:ls -aH $PATH | grep -Fxv -e . -e ..

Es gibt einfachere Lösungen in bash und in zsh .

Gilles 'SO - hör auf böse zu sein'
quelle
Dies setzt voraus, dass $PATHdas gesetzt ist und keine leeren Komponenten enthält und dass Komponenten nicht wie Prädikate (oder ls-Optionen) aussehen. Einige davon ignorieren auch Punktdateien.
Stéphane Chazelas
@StephaneChazelas Ja, ok. Abgesehen von leeren Bauteilen fällt dies direkt unter die Kategorie „Mach das nicht“ - PATH liegt unter deiner Kontrolle.
Gilles 'SO - hör auf böse zu sein'
Es funktioniert immer noch nicht, wenn das leere Element das letzte ist (wie es normalerweise ist). (außer in yashund zshin sh Emulation).
Stéphane Chazelas
In deinem find. -pruneverhindert das Auflisten von Verzeichnissen. Sie möchten wahrscheinlich -Lstatt -Hwie Sie möchten Symlinks (gemeinsam für ausführbare Dateien) enthalten. -perm -100gibt keine Garantie dafür, dass die Datei von Ihnen ausführbar ist (und möglicherweise (unwahrscheinlich) ausführbare Dateien ausschließt).
Stéphane Chazelas
4

Das habe ich mir ausgedacht:

IFS=':';for i in $PATH; do test -d "$i" && find "$i" -maxdepth 1 -executable -type f -exec basename {} \;; done

BEARBEITEN : Es scheint, dass dies der einzige Befehl ist, der beim Lesen einiger Dateien im bin-Verzeichnis durch einen Apache-Benutzer keine SELinux-Warnung auslöst.

jcubic
quelle
5
Warum das for? IFS=:; find $PATH -maxdepth 1 -executable -type f -printf '%f\n'
Manatwork
@manatwork funktioniert es für nicht vorhandene Pfade?
jcubic
@manatwork wusste nicht, dass Sie das tun können. müssen mehr über IFS lesen.
jcubic
3
Dies setzt voraus, dass $PATHgesetzt ist und keine Platzhalterzeichen und keine leeren Komponenten enthält. Das setzt auch die GNU-Implementierung von vorausfind .
Stéphane Chazelas
2
Aufgrund von -type fanstelle von (GNU-spezifisch) -xtype fwerden auch Symlinks weggelassen. Dadurch wird auch nicht der Inhalt von $PATHKomponenten aufgelistet, bei denen es sich um Symlinks handelt.
Stéphane Chazelas
3

Wie wäre es damit

find ${PATH//:/ } -maxdepth 1 -executable

Die Zeichenfolgensubstitution wird mit Bash verwendet.


quelle
3
Das setzt voraus, dass $PATHgesetzt ist, keine Platzhalter oder Leerzeichen enthält, keine leeren Komponenten enthält. Das setzt voraus, dass GNU auch findet. Beachten Sie, dass dies ${var//x/y}die kshSyntax ist (wird auch von zsh und bash unterstützt). Genau genommen setzt dies auch voraus, dass $ PATH-Komponenten auch keine findPrädikate sind.
Stéphane Chazelas
1
Das setzt auch voraus, dass $PATHKomponenten keine Symlinks sind.
Stéphane Chazelas
@StephaneChazelas: Danke! Mit anderen Worten, üblicher Fall.
Die Einstellung IFS=:ist robuster als diese Ersetzung. Pfade mit Leerzeichen sind unter Windows keine Seltenheit. Symbolische Verknüpfungen sind weit verbreitet, aber das lässt sich leicht lösen -H.
Gilles 'SO - hör auf böse zu sein'
@ Gilles: natürlich. Ich sehe jedoch keinen vernünftigen Anwendungsfall für diese Frage, daher ist keine kugelsichere Antwort erforderlich.
1

Wenn Sie Python in Ihrer Shell ausführen können, kann auch der folgende (lächerlich lange) Einzeiler verwendet werden:

python -c 'import os;import sys;output = lambda(x) : sys.stdout.write(x + "\n"); paths = os.environ["PATH"].split(":") ; listdir = lambda(p) : os.listdir(p) if os.path.isdir(p) else [ ] ; isfile = lambda(x) : True if os.path.isfile(os.path.join(x[0],x[1])) else False ; isexe = lambda(x) : True if os.access(os.path.join(x[0],x[1]), os.X_OK) else False ; map(output,[ os.path.join(p,f) for p in paths for f in listdir(p) if isfile((p,f)) and isexe((p,f)) ])'

Dies war für mich meistens eine lustige Übung, um herauszufinden, ob es mit einer einzigen Zeile Python-Code möglich ist, ohne die Funktion 'exec' zu verwenden. In einer besser lesbaren Form und mit einigen Kommentaren sieht der Code folgendermaßen aus:

import os
import sys

# This is just to have a function to output something on the screen.
# I'm using python 2.7 in which 'print' is not a function and cannot
# be used in the 'map' function.
output = lambda(x) : sys.stdout.write(x + "\n")

# Get a list of the components in the PATH environment variable. Will
# abort the program is PATH doesn't exist
paths = os.environ["PATH"].split(":")

# os.listdir raises an error is something is not a path so I'm creating
# a small function that only executes it if 'p' is a directory
listdir = lambda(p) : os.listdir(p) if os.path.isdir(p) else [ ]

# Checks if the path specified by x[0] and x[1] is a file
isfile = lambda(x) : True if os.path.isfile(os.path.join(x[0],x[1])) else False

# Checks if the path specified by x[0] and x[1] has the executable flag set
isexe = lambda(x) : True if os.access(os.path.join(x[0],x[1]), os.X_OK) else False

# Here, I'm using a list comprehension to build a list of all executable files
# in the PATH, and abusing the map function to write every name in the resulting
# list to the screen.
map(output, [ os.path.join(p,f) for p in paths for f in listdir(p) if isfile((p,f)) and isexe((p,f)) ])
brm
quelle
0
#!/usr/bin/env python
import os
from os.path import expanduser, isdir, join, pathsep

def list_executables():
    paths = os.environ["PATH"].split(pathsep)
    executables = []
    for path in filter(isdir, paths):
        for file_ in os.listdir(path):
            if os.access(join(path, file_), os.X_OK):
                executables.append(file_)
    return executables
Steven
quelle