Liste tous les fichiers / binaires dans le PATH actuel

10

Existe-t-il un moyen "facile" d'exécuter une commande de style "ls -la" pour répertorier tous les fichiers / binaires exécutables dans le CHEMIN actuel?

(J'ai l'intention de diriger la sortie dans grep, pour rechercher des commandes avec des préfixes inconnus mais essentiellement des "noms" connus, le genre de cas où l'auto-complétion / tabulation dans bash est essentiellement inutile. Donc, une sorte de "auto inverse" fonctionnalité complète "...)

pme
la source
Pouvez-vous donner des exemples? En quoi est-ce différent avec ls -la?
John Siu
"ls -la" / "ls -a" ne répertorie que les fichiers de votre répertoire actuel (pwd). Je veux lister tous les fichiers (exécutables) dans tous les répertoires inclus dans PATH.
sme

Réponses:

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
la source
Bien, c'est vraiment ce que je cherchais. Il inclut même des binaires exécutables dans le répertoire courant. Merci.
sme
Fonctionne bien ... en bash.
Emanuel Berg
existe-t-il un moyen de répertorier le chemin de chacun de ces éléments sans le faire which $(compgen -A function -abck)?
h3rrmiller
Je ne pouvais pas trouver de meilleure alternative.
Nykakin
3

Voici une fonction qui répertorie le contenu des répertoires $PATH. Si des arguments sont passés, la fonction répertorie uniquement les commandes dont le nom contient l'un des arguments. Les arguments sont interprétés comme des motifs globaux.

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
}

Comme beaucoup de choses, c'est plus facile dans zsh.

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

Le ^caractère dans l' expansion des paramètres entraîne l'ajout du texte concaténé avec le tableau à chaque élément du tableau, par exemple les path=(/bin /usr/bin); echo $^path/fooimpressions /bin/foo /usr/bin/foo.
/*$^@*ressemble à une insulte de bande dessinée mais est en fait le caractère ordinaire /, le caractère générique *, le paramètre spécial $@(le tableau des paramètres de position) avec le ^modificateur, et encore *.
(N:t)est le qualificatif glob N pour obtenir une expansion vide s'il n'y a pas de correspondance suivi du modificateur d'historique t pour ne conserver que le nom de base («queue») de chaque correspondance.

Plus cryptique, évite l'appel externe mais cela n'a qu'un intérêt cosmétique:

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

Vous pouvez en fait rechercher la aproposcommande, qui recherche des pages de manuel de commandes dont la courte description contient un mot-clé. Une limitation est que cela ne trouve que les commandes qui ont une page de manuel.

Gilles 'SO- arrête d'être méchant'
la source
Dans la fonction zsh, la seconde ^semble n'entraîner aucune sortie pour un appel "sans arguments"? Si vous le supprimez, vous pouvez tous les répertorier et toujours rechercher des mots clés uniques (mais pas une liste d'entre eux). Le (Non:t)semble dire que les astérisques devraient être élargis? Impossible de comprendre ce dernier.
Emanuel Berg
@EmanuelBerg D'accord, merci pour le correctif. J'ai ajouté une explication du bruit de ligne.
Gilles 'SO- arrête d'être méchant'
OK, voyons: s'il n'y a pas d'arguments, vous ne définissez "eux" rien, parce que ce qui était là (quand il n'y en avait pas) perturbait encore ce que vous avez fait ensuite? De plus, je n'ai jamais vu de minuscules path, mais quand je l'exécute dans le shell, c'est bien $ PATH mais avec des espaces au lieu de :. Le reste est limpide :)
Emanuel Berg
@EmanuelBerg Non: s'il n'y a pas d'arguments, je définis le tableau d'arguments comme un tableau à un élément contenant la chaîne vide. De cette façon, aucun argument ne signifie que chaque nom contenant la chaîne vide correspond, c'est-à-dire que chaque nom correspond. $pathest une fonctionnalité zsh: c'est un paramètre lié , un tableau qui est automatiquement mis à jour lorsqu'il PATHest mis à jour et vice versa.
Gilles 'SO- arrête d'être méchant'
Aha, maintenant je vois! Wow, c'était peu orthodoxe!
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" ; 
}

la recherche ne correspond qu'à: avoir au moins un bit "x" (exécutable) défini, et qui n'est pas un répertoire.

et l'utiliser avec une liste d'expressions régulières à trouver:

findinpath awk sed '\.sh$'
Olivier Dulac
la source
regexp "." vous montrera tout
Olivier Dulac
avec l'IFS régulier, vous pouvez trouver des entrées en double dans votre $ PATH avec:echo $PATH | tr ':' '\n' | sort | uniq -d
Olivier Dulac
1
J'ai essayé le code pour toutes les réponses et c'est le seul qui m'a réellement donné ce que je cherchais (chemins d'accès complets à chaque instance d'une commande donnée sur le CHEMIN).
Chris Page
Je suis content que cela ait aidé :)
Olivier Dulac
1
for i in $(echo $PATH | sed -e 's/\:/\ /g'); do find "$i" -perm +rwx -exec echo {} \; 2> /dev/null; done

nous faisons d'abord écho $PATHdans sed et remplaçons ":" par "".

puis nous faisons une recherche sur chacune de ces choses pour trouver des fichiers avec rwx et les faire écho.

2> /dev/nullest donc findpas imprimer des erreurs

h3rrmiller
la source
3
vous avez besoin d'un -maxdepth 1et -type fdans votre recherche, sinon vous trouverez des sous-répertoires et leurs fichiers (ce que la recherche PATH ne fera pas). De plus, votre test de permission est bizarre - devrait juste pour +x, je pense?
derobert
Cela ne traitera pas les cas de bord où une entrée vide valide est la même que «.», Par exemple :/binou /bin::/usr/bin. Essayez d'ajouter s/::/:.:/;s/^:/.:/;s/:$/:./à la sedcommande.
Arcege
En fait, vous findpouvez rechercher plus de chemins, vous pouvez donc le faire sans la boucle: find $(echo $PATH | sed -e 's/\:/\ /g') -perm +rwx …bien sûr, les noms de répertoire contenant des espaces vont le gâcher, mais celui basé sur la boucle a le même problème de toute façon.
manatwork du
@manatwork vous avez raison. J'ai ajouté des citations pour résoudre ce problème tout à l'heure
h3rrmiller
Désolé, cela ne résout rien. Le problème est de remplacer les deux-points par des espaces pour permettre la séparation des mots. Vous transformez donc «/ foo bar: / fiz baz» en «/ foo bar / fiz baz», puis vous passez cela à for. Il forva donc parcourir une liste de 4 mots. Pour manipuler le découpage des mots mieux définir la IFSfonction de votre besoin: IFS=':'; find $PATH -perm +rwx ….
manatwork