Liste tous les binaires de $ PATH

30

Y a-t-il une ligne qui listera tous les exécutables de $ PATH dans bash.

jcubic
la source

Réponses:

38

Ce n'est pas une réponse, mais cela montre du binaire, une commande que vous pourriez exécuter

compgen -c

(en supposant bash)

Autres commandes utiles

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
la source
1
Bon à savoir cette commande, et j'ai en fait besoin d'exécutables pour l'achèvement. Peut-être que j'utilise cette commande à la place.
jcubic
Notez qu'il comprend également des fonctions intégrées, des fonctions, des mots clés (comme in, {...) et des alias.
Stéphane Chazelas
Monsieur, j'ai mis à jour .. j'avais sauvegardé dans mon brouillon, il y a longtemps que j'ai trouvé sur ce site ..
Rahul Patil
@jcubic, les shells le font déjà pour l'achèvement de la commande Pourquoi le faire à la main?
vonbrand
@vonbrand Je travaille sur le shell en javascript / php et j'exécute le shell en mode non interactif.
jcubic
15

Avec zsh:

whence -pm '*'

Ou:

print -rl -- $commands

(notez que pour les commandes qui apparaissent dans plusieurs composants de $PATH, elles répertorieront uniquement le premier).

Si vous voulez les commandes sans les chemins d'accès complets et triées pour faire bonne mesure:

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

(autrement dit, récupérez les clés de ce tableau associatif au lieu des valeurs).

Stéphane Chazelas
la source
Je n'ai pas mentionné que j'utilise bash.
jcubic
5

Dans n'importe quel shell POSIX, sans utiliser de commande externe (en supposant qu'il printfest intégré, sinon revenir à echo) sauf pour le tri final, et en supposant qu'aucun nom exécutable ne contient de nouvelle ligne:

{ 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

Si vous n'avez aucun composant vide dans $PATH(utilisez à la .place), ni des composants commençant par -, ni des caractères génériques \[?*dans les composants PATH ou les noms d'exécutables, et aucun exécutable commençant par ., vous pouvez simplifier ceci pour:

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

Utilisation de POSIX findet sed:

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

Si vous êtes prêt à répertorier le fichier rare non exécutable ou le fichier non régulier dans le chemin, il existe un moyen beaucoup plus simple:

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

Cela saute les fichiers de points; si vous en avez besoin, ajoutez le -Adrapeau à lssi le vôtre l'a, ou si vous voulez vous en tenir à POSIX:ls -aH $PATH | grep -Fxv -e . -e ..

Il existe des solutions plus simples en bash et en zsh .

Gilles 'SO- arrête d'être méchant'
la source
Cela suppose qu'il $PATHest défini et ne contient pas de composants vides, et que les composants ne ressemblent pas à des prédicats de recherche (ou aux options ls). Certains d'entre eux ignoreront également les fichiers dot.
Stéphane Chazelas
@StephaneChazelas Oui, d'accord. Hormis les composants vides, cela tombe carrément sous la catégorie «ne faites pas ça» - PATH est sous votre contrôle.
Gilles 'SO- arrête d'être méchant'
Cela ne fonctionne toujours pas si l'élément vide est le dernier (comme d'habitude). (sauf dans yashet zshen émulation sh).
Stéphane Chazelas
Dans le vôtre find. -pruneempêchera la liste des répertoires. Vous voulez probablement -Lau lieu de -Hcomme vous voulez inclure des liens symboliques (communs aux exécutables). -perm -100ne donne aucune garantie que le fichier soit exécutable par vous (et pourrait (peu probable) exclure les fichiers exécutables).
Stéphane Chazelas
4

Je suis venu avec ceci:

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

EDIT : Il semble que c'est la seule commande qui ne déclenche pas l'alerte SELinux lors de la lecture de certains fichiers du répertoire bin par un utilisateur apache.

jcubic
la source
5
Pourquoi for? IFS=:; find $PATH -maxdepth 1 -executable -type f -printf '%f\n'
manatwork
@manatwork fonctionnera-t-il pour des chemins non existants?
jcubic
@manatwork ne savait pas que vous pouviez faire ça. besoin d'en savoir plus sur IFS.
jcubic
3
Cela suppose qu'il $PATHest défini et ne contient pas de caractères génériques et ne contient pas de composants vides. Cela suppose également l'implémentation GNU de find.
Stéphane Chazelas
2
En raison de -type fau lieu de (spécifique à GNU) -xtype f, cela supprimera également les liens symboliques. Cela ne répertoriera pas non plus le contenu des $PATHcomposants qui sont des liens symboliques.
Stéphane Chazelas
3

Que dis-tu de ça

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

La substitution de chaîne est utilisée avec Bash.


la source
3
Cela suppose qu'il $PATHest défini, ne contient pas de caractères génériques ou vides, ne contient pas de composants vides. Cela suppose également que GNU find. Notez que ${var//x/y}c'est la kshsyntaxe (également prise en charge par zsh et bash). Strictement parlant, cela suppose également que les composants $ PATH ne sont pas non plus des findprédicats.
Stéphane Chazelas
1
Cela suppose également que les $PATHcomposants ne sont pas des liens symboliques.
Stéphane Chazelas
@StephaneChazelas: Merci! En d'autres termes, cas habituel.
Le réglage IFS=:est plus robuste que cette substitution. Les chemins avec des espaces ne sont pas si rares sous Windows. Les liens symboliques sont assez courants, mais cela se résout facilement avec -H.
Gilles 'SO- arrête d'être méchant'
@Gilles: bien sûr. Cependant, je ne vois aucun cas d'utilisation raisonnable pour cette question, il n'est donc pas nécessaire de répondre à toute épreuve.
1

Si vous pouvez exécuter python dans votre shell, le one-liner suivant (ridiculement long) peut également être utilisé:

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)) ])'

C'était surtout un exercice amusant pour moi pour voir si cela pouvait être fait en utilisant une ligne de code python sans avoir recours à la fonction 'exec'. Sous une forme plus lisible et avec quelques commentaires, le code ressemble à ceci:

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
la source
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
la source