Listar todos os binários de $ PATH

30

Existe uma linha que listará todos os executáveis ​​de $ PATH no bash.

jcubic
fonte

Respostas:

38

Esta não é uma resposta, mas está mostrando binário, um comando que você pode executar

compgen -c

(assumindo bash)

Outros comandos úteis

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
fonte
1
É bom conhecer esse comando e eu realmente preciso de executáveis ​​para conclusão. Talvez eu use esse comando.
jcubic
Observe que também inclui builtins, funções, palavras-chave (como in, {...) e aliases.
Stéphane Chazelas 22/03
Senhor, eu atualizei .. Eu salvei no meu rascunho, há muito tempo que encontrei neste site ..
Rahul Patil
@ jcubic, as conchas já fazem isso para a conclusão do comando Por que fazer manualmente?
vonbrand
@ vonbrand Estou trabalhando no shell em javascript / php e estou executando o shell no modo não interativo.
jcubic
15

Com zsh:

whence -pm '*'

Ou:

print -rl -- $commands

(observe que, para comandos que aparecem em mais de um componente $PATH, eles listarão apenas o primeiro).

Se você deseja os comandos sem os caminhos completos e classificados por uma boa medida:

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

(ou seja, obtenha as chaves dessa matriz associativa em vez dos valores).

Stéphane Chazelas
fonte
Eu não mencionei que estou usando o bash.
jcubic
5

Em qualquer shell POSIX, sem usar nenhum comando externo (assumindo que printfestá embutido, se não voltar a echo), exceto pela classificação final e assumindo que nenhum nome executável contém uma nova linha:

{ 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

Se você não possui nenhum componente vazio $PATH(use em .vez disso), nem componentes iniciados com -, nem caracteres curinga \[?*nos componentes PATH ou nos nomes de executáveis, nem nos executáveis ​​iniciados com ., você pode simplificar isso para:

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

Usando POSIX finde sed:

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

Se você deseja listar o arquivo não-executável raro ou o arquivo não-regular no caminho, há uma maneira muito mais simples:

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

Isso pula arquivos de ponto; se você precisar deles, adicione o -Asinalizador lsse o seu tiver ou se você deseja manter o POSIX:ls -aH $PATH | grep -Fxv -e . -e ..

Existem soluções mais simples no bash e no zsh .

Gilles 'SO- parar de ser mau'
fonte
Isso pressupõe que $PATHestá definido e não contém componentes vazios e que esses componentes não parecem encontrar predicados (ou opções ls). Alguns deles também ignoram arquivos de ponto.
Stéphane Chazelas 22/03
@StephaneChazelas Yeah, ok. Além dos componentes vazios, isso se enquadra diretamente na categoria "não faça isso" - o PATH está sob seu controle.
Gilles 'SO- stop be evil'
Ainda não funciona se o elemento vazio for o último (como geralmente é). (exceto em yashe zshem emulação sh).
Stéphane Chazelas 22/03
No seu find. -pruneimpedirá a listagem de diretórios. Você provavelmente deseja, em -Lvez de -Hincluir links simbólicos (comuns para executáveis). -perm -100não garante que o arquivo seja executável por você (e pode (improvável) excluir arquivos executáveis).
Stéphane Chazelas 22/03
4

Eu vim com isso:

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

EDIT : Parece que este é o único comando que não aciona o alerta SELinux ao ler alguns dos arquivos no diretório bin pelo usuário apache.

jcubic
fonte
5
Por que o for? IFS=:; find $PATH -maxdepth 1 -executable -type f -printf '%f\n'
manatwork
@manatwork funcionará para caminhos inexistentes?
jcubic
@manatwork não sabia que você pode fazer isso. precisa ler mais sobre o IFS.
jcubic
3
Isso pressupõe que $PATHestá definido e não contém caracteres curinga e não contém componentes vazios. Isso também assume a implementação GNU de find.
Stéphane Chazelas
2
Por causa de em -type fvez de (específico do GNU) -xtype f, isso também omitirá links simbólicos. Isso também não listará o conteúdo dos $PATHcomponentes que são links simbólicos.
Stéphane Chazelas 22/03
3

Que tal agora

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

A substituição de cadeia é usada com o Bash.


fonte
3
Isso pressupõe que $PATHestá definido, não contém caracteres curinga ou caracteres em branco, não contém componentes vazios. Isso pressupõe que o GNU encontre também. Observe que ${var//x/y}é uma kshsintaxe (também suportada pelo zsh e bash). A rigor, também assume que os componentes $ PATH também não são findpredicados.
Stéphane Chazelas 22/03
1
Isso também pressupõe que os $PATHcomponentes não sejam links simbólicos.
Stéphane Chazelas 22/03
@StephaneChazelas: Obrigado! Em outras palavras, caso usual.
A configuração IFS=:é mais robusta do que fazer essa substituição. Caminhos com espaços não são tão incomuns no Windows. Links simbólicos são bastante comuns, mas isso é facilmente resolvido -H.
Gilles 'SO- stop being evil'
@ Gilles: é claro. no entanto, não vejo nenhum caso de uso razoável para esta pergunta; portanto, não há necessidade de uma resposta à prova de balas.
1

Se você pode executar o python no seu shell, o seguinte (ridiculamente longo) one-liner também pode ser usado:

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

Este foi principalmente um exercício divertido para mim, para ver se poderia ser feito usando uma linha de código python sem recorrer ao uso da função 'exec'. De uma forma mais legível e com alguns comentários, o código fica assim:

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
fonte
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
fonte