Listar todos os arquivos / binários no PATH atual

10

Existe uma maneira "fácil" de executar um comando no estilo "ls -la" para listar todos os arquivos / binários executáveis ​​no PATH atual?

(Pretendo canalizar a saída para o grep, para procurar comandos com prefixos desconhecidos, mas basicamente com "nomes" conhecidos, o tipo de caso em que o preenchimento automático / tabulação no bash é essencialmente inútil. recurso completo "...)

sme
fonte
Você pode dar exemplos? Como isso será diferente ls -la?
John Siu
"ls -la" / "ls -a" lista apenas os arquivos em seu diretório atual (pwd). Quero listar todos os arquivos (executáveis) em todos os diretórios incluídos no PATH.
sme

Respostas:

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
fonte
Bom, é isso que eu tenho procurado. Inclusive inclui binários executáveis ​​no diretório atual. Obrigado.
sme
Funciona bem ... no bash.
Emanuel Berg
existe uma maneira de listar o caminho de cada um deles sem fazer which $(compgen -A function -abck)?
H3rrmiller
Não consegui encontrar nenhuma alternativa melhor.
Nykakin
3

Aqui está uma função que lista o conteúdo dos diretórios $PATH. Se passados ​​argumentos, a função lista apenas comandos cujo nome contém um dos argumentos. Os argumentos são interpretados como padrões glob.

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
}

Como muitas coisas, isso é mais fácil no zsh.

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

O ^caractere na expansão de parâmetro faz com que o texto concatenado com a matriz seja adicionado a cada elemento da matriz, por exemplo, path=(/bin /usr/bin); echo $^path/fooimpressões /bin/foo /usr/bin/foo.
/*$^@*parece um insulto à história em quadrinhos, mas na verdade é o caractere comum /, o curinga *, o parâmetro especial $@(a matriz do parâmetro posicional) com o ^modificador e, novamente *.
(N:t)é o qualificador global N para obter uma expansão vazia se não houver correspondência seguida pelo modificador de histórico t para manter apenas o nome da base ("cauda") de cada correspondência.

Mais enigmático, evita a chamada externa, mas isso é apenas de interesse cosmético:

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

De fato, você pode estar procurando pelo aproposcomando, que procura por páginas de manual de comandos cuja descrição curta contém uma palavra-chave. Uma limitação é que isso encontra apenas comandos que possuem uma página de manual.

Gilles 'SO- parar de ser mau'
fonte
Na função zsh, o segundo ^parece resultar em nenhuma saída para uma chamada "sem argumentos"? Se você largá-lo, poderá listá-los todos e ainda procurar palavras-chave únicas (mas não uma lista delas). O (Non:t)parece dizer que asteriscos deve ser expandido? Não foi possível descobrir esse último.
Emanuel Berg
@EmanuelBerg Certo, obrigado pela correção. Eu adicionei uma explicação do ruído da linha.
Gilles 'SO- stop be evil'
OK, vamos ver: se não há argumentos, você define "eles" para nada, porque o que estava lá (quando não havia), ainda assim de alguma forma atrapalhava o que você fez a seguir? Além disso, nunca vi letras minúsculas path, mas quando o executo no shell, é de fato $ PATH, mas com espaços em vez de :. O resto é cristal :) clara
Emanuel Berg
@EmanuelBerg Não: se não houver argumentos, defino a matriz de argumentos como uma matriz de um elemento que contém a string vazia. Dessa forma, nenhum argumento significa que todos os nomes que contêm a string vazia correspondem, ou seja, todos os nomes correspondem. $pathé um recurso zsh: é um parâmetro vinculado , uma matriz que é atualizada automaticamente quando PATHé atualizada e vice-versa.
Gilles 'SO- stop be evil' (
Aha, agora eu vejo! Uau, isso foi pouco ortodoxo!
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" ; 
}

a descoberta corresponde apenas a: tem pelo menos um bit "x" (executável) definido e esse não é um diretório.

e use-o com uma lista de regexp a ser encontrada:

findinpath awk sed '\.sh$'
Olivier Dulac
fonte
regexp "." mostrará tudo
Olivier Dulac
com o IFS regular, você pode encontrar entradas duplicadas no seu $ PATH com:echo $PATH | tr ':' '\n' | sort | uniq -d
Olivier Dulac
1
Eu tentei o código para todas as respostas e este é o único que realmente me deu o que estava procurando (caminhos completos para todas as instâncias de um determinado comando no PATH).
Chris Page
Eu estou contente que ajudou :)
Olivier Dulac
1
for i in $(echo $PATH | sed -e 's/\:/\ /g'); do find "$i" -perm +rwx -exec echo {} \; 2> /dev/null; done

primeiro ecoamos $PATHem sed e substituímos ":" por "".

em seguida, localizamos cada uma dessas coisas para encontrar arquivos com o rwx e ecoá-los.

2> /dev/nullé assim findnão vai imprimir erros

h3rrmiller
fonte
3
você precisa de um -maxdepth 1e -type fna sua localização, caso contrário, você encontrará subdiretórios e seus arquivos (que a pesquisa PATH não precisará). Além disso, seu teste de permissão é estranho - deveria apenas +x, eu acho?
Derobert
Isso não manipula os casos de borda onde uma entrada em branco válida é igual a '.', Por exemplo :/binou /bin::/usr/bin. Tente adicionar s/::/:.:/;s/^:/.:/;s/:$/:./ao sedcomando.
Arcege
Na verdade, é findpossível pesquisar mais caminhos, para que você possa fazê-lo sem o loop: find $(echo $PATH | sed -e 's/\:/\ /g') -perm +rwx …é claro que os nomes de diretórios que contêm espaços atrapalharão, mas o baseado no loop tem o mesmo problema.
precisa saber é
@ manatwork você está certo. Eu adicionei aspas para resolver essa questão só agora
h3rrmiller
Desculpe, isso não resolve nada. O problema está em substituir os dois pontos por espaços para permitir a divisão de palavras. Então você transforma “/ foo bar: / fiz baz” em “/ foo bar / fiz baz” e depois passa isso para for. Então for, repetirá uma lista de 4 palavras. Para manipular repartição de palavras melhor definir o IFSacordo com sua necessidade: IFS=':'; find $PATH -perm +rwx ….
manatwork