Procure por arquivos executáveis ​​usando o comando find


113

Que tipo de parâmetro / sinalizador posso usar com o findcomando Unix para pesquisar executáveis?


digite 'homem encontrar'. Acho que '-executável' é a opção que você deseja.
sje397

3
find -executable... mas isso não garante que todos os arquivos listados sejam realmente executados
William

1
Nem todas as implementações de findsão criadas iguais. A opção recomendada por @ sje397 e @William pode não estar disponível. É melhor usar a solução aceita mostrada abaixo.
LS


Eu não gosto de todas as propostas mostradas abaixo que são baseadas em permissões de arquivo. Argumentação: para meu sistema operacional GNU (Ubuntu), é possível definir o sinalizador "x" (executável) para, por exemplo, arquivo de texto ASCII. Nenhuma imitação impediu que esta operação fosse concluída com sucesso. Ele precisa apenas de um pequeno erro / bug para que vários arquivos não intencionais tenham o sinalizador x atribuído. Portanto, soluções gniourf_gniourf 'são minhas favoritas. No entanto, tem a desvantagem de que, para executáveis ​​de compilação cruzada, é necessário um emulador ou dispositivo de destino.
Na13-c

Respostas:


173

Nas versões GNU do find, você pode usar -executable:

find . -type f -executable -print

Para versões BSD de find, você pode usar -permcom +uma máscara octal:

find . -type f -perm +111 -print

Neste contexto, "+" significa "qualquer um desses bits está definido" e 111 são os bits de execução.

Observe que isso não é idêntico ao -executablepredicado em GNU find. Em particular, -executabletesta se o arquivo pode ser executado pelo usuário atual, enquanto -perm +111apenas testa se alguma permissão de execução está definida.

Versões mais antigas do GNU find também suportam a -perm +111sintaxe, mas a partir de 4.5.12 esta sintaxe não é mais suportada. Em vez disso, você pode usar-perm /111 para obter esse comportamento.


Erro find: invalid mode ‘+111’em findutils 4.5.11 4.fc20.
sourcejedi

1
@sourcejedi Obrigado. Na verdade, eu estava falando apenas sobre versões não GNU de find (BSD, em particular), mas versões anteriores de GNU find também suportavam essa sintaxe. Em versões mais recentes, você terá que usar em /vez de +. Veja a resposta atualizada para mais detalhes.
Laurence Gonsalves

Na verdade, eu interpretei mal sua resposta. Desculpe por tornar isso mais complicado :).
sourcejedi

Se links simbólicos para arquivos executáveis também deve ser encontrada, incluem a -Lopção: find -L ....
mklement0

Levei um tempo para entender as implicações de "não idêntico ao predicado -executável" e "apenas testa se alguma permissão de execução está definida": isso significa que -perm +111pode gerar falsos positivos , ou seja, arquivos que o usuário atual não pode realmente executar. Não há como emular -executabletestando apenas as permissões, porque o que é necessário é relacionar o usuário do arquivo e a identidade do grupo ao usuário atual .
mklement0

35

Dica do chapéu para @ gniourf_gniourf por esclarecer um equívoco fundamental.

Esta resposta tenta fornecer uma visão geral das respostas existentes e discutir suas sutilezas e méritos relativos , bem como fornecer informações básicas , especialmente no que diz respeito à portabilidade .

Encontrar arquivos executáveis ​​pode se referir a dois casos de uso distintos :

  • centrado no usuário : encontre arquivos executáveis pelo usuário atual .
  • centralizado no arquivo : encontre arquivos que tenham (um ou mais) bits de permissão executáveis definidos .

Observe que em qualquer cenário pode fazer sentido usar emfind -L ... vez de apenas find ...para encontrar links simbólicos para executáveis .

Observe que o caso mais simples centrado em arquivo - procurando por executáveis ​​com o bit de permissões executáveis ​​definido para TODAS as três entidades de segurança (usuário, grupo, outro) - normalmente , mas não necessariamente produzirá os mesmos resultados que o cenário centrado no usuário - e é importante entender a diferença.

Centrado no usuário ( -executable)

  • A resposta aceita recomenda com louvor -executable, SE GNU find estiver disponível.

    • GNU findvem com a maioria do Linux distros
      • Em contraste, plataformas baseadas em BSD, incluindo macOS, vêm com BSD find, que é menos poderoso.
    • Conforme o cenário exige, -executablecorresponde apenas aos arquivos que o usuário atual pode executar (há casos extremos. [1] ).
  • A alternativa BSD find oferecida pela resposta aceita ( -perm +111) responde a uma pergunta diferente , centrada em arquivo (como a própria resposta afirma).

    • Usar apenas -permpara responder à pergunta centrada no usuário é impossível , porque o que é necessário é relacionar o usuário do arquivo e a identidade do grupo ao usuário atual , ao passo que -permsó pode testar as permissões do arquivo .
      Usando apenas recursos POSIXfind , a pergunta não pode ser respondida sem envolver utilitários externos.
    • Assim, o melhor que -permpodemos fazer (por si só) é uma aproximação de -executable. Talvez uma aproximação mais próxima do que -perm +111é-perm -111 , para encontrar arquivos que têm o bit executável definido para TODOS os princípios de segurança (usuário, grupo, outro) - isso me parece o cenário típico do mundo real. Como um bônus, ele também é compatível com POSIX (use find -Lpara incluir links simbólicos, veja mais abaixo para uma explicação):

      find . -type f -perm -111  # or: find . -type f -perm -a=x
  • A resposta de gniourf_gniourf fornece um equivalente verdadeiro e portátil de-executable usar-exec test -x {} \;, embora às custas do desempenho .

    • Combinar -exec test -x {} \; com -perm +111(ou seja, arquivos com pelo menos um conjunto de bits executáveis) pode ajudar no desempenho, pois execnão precisa ser invocado para todos os arquivos (o seguinte usa o equivalente compatível com POSIX de BSD find -perm +111/ GNU find -perm /111; veja mais abaixo para uma explicação) :

      find . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \) -exec test -x {} \; -print

Centrado no arquivo (-perm )

  • Para responder a perguntas centradas em arquivos , é suficiente usar o -permprimário compatível com POSIX (conhecido como teste na terminologia de localização do GNU).
    • -perm permite que você teste quaisquer permissões de arquivo, não apenas a executabilidade.
    • As permissões são especificadas como modos octal ou simbólico . Os modos octais são números octais (por exemplo, 111), enquanto os modos simbólicos são strings (por exemplo, a=x).
    • Os modos simbólicos identificam os principais de segurança como u(usuário), g(grupo) e o(outro) ou apara se referir a todos os três. As permissões são expressas como xexecutáveis, por exemplo, e atribuídas aos principais usando operadores =, +e -; para uma discussão completa, incluindo os modos octais, consulte a especificação POSIX do chmodutilitário .
    • No contexto de find:
      • Prefixar um modo com- (por exemplo, -ug=x) significa: combinar arquivos que têm todas as permissões especificadas (mas os arquivos correspondentes podem ter permissões adicionais).
      • Não ter NENHUM prefixo (por exemplo 755) significa: corresponder aos arquivos que possuem este completo, exato de permissões.
      • Advertência : GNU find e BSD find implementam um prefixo não padrão adicional com a lógica de conjunto de bits de permissão especificada , mas fazem isso com sintaxe incompatível :
        • BSD encontrar: +
        • GNU find: / [2]
      • Portanto, evite essas extensões, se seu código deve ser portátil .
  • Os exemplos abaixo demonstram respostas portáteis a várias perguntas centradas em arquivos.

Exemplos de comando centrado em arquivo

Nota:

  • Os exemplos a seguir são compatíveis com POSIX , o que significa que devem funcionar em qualquer implementação compatível com POSIX, incluindo GNU find e BSD find; especificamente, isso requer:
    • NÃO usa prefixos de modo não padrão +ou /.
    • Usando as formas POSIX das primárias do operador lógico :
      • !para NOT (GNU find e BSD find também permitem -not); note que \!é usado nos exemplos para proteger !de expansões de histórico de shell
      • -apara AND (GNU find e BSD find também permitem -and)
      • -opara OR (GNU find e BSD find também permitem -or)
  • Os exemplos usam modos simbólicos , porque são mais fáceis de ler e lembrar.
    • Com o prefixo de modo -, os operadores =e +podem ser usados ​​alternadamente (por exemplo, -u=xé equivalente a -u+x- a menos que você aplique -xmais tarde, mas não há porque fazer isso).
    • Use ,para entrar em modos parciais; A lógica AND está implícita; por exemplo, -u=x,g=xsignifica que o bit executável do usuário e do grupo deve ser definido.
    • Os modos não podem por si próprios expressar correspondência negativa no sentido de "corresponder apenas se este bit NÃO estiver definido"; você deve usar uma -permexpressão separada com o NOT primário !,.
  • Observe que as primárias de find (como -print, ou -perm; também conhecidas como ações e testes em GNU find) são implicitamente associadas a-a (AND lógico), -oe possivelmente parênteses (com escape de \(e\) para o shell) são necessários para implementar a lógica OR.
  • find -L ... em vez de apenas find ... é usado para também corresponder links simbólicos para executáveis
    • -Linstrui o find para avaliar os alvos dos links simbólicos em vez dos próprios links simbólicos; portanto, sem -L, -type firia ignorar os links simbólicos completamente.
# Match files that have ALL executable bits set - for ALL 3 security
# principals (u (user), g (group), o (others)) and are therefore executable
# by *anyone*.
# This is the typical case, and applies to executables in _system_ locations
# (e.g., /bin) and user-installed executables in _shared_ locations
# (e.g., /usr/local/bin), for instance. 
find -L . -type f -perm -a=x  # -a=x is the same as -ugo=x

# The POSIX-compliant equivalent of `-perm +111` from the accepted answer:
# Match files that have ANY executable bit set.
# Note the need to group the permission tests using parentheses.
find -L . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \)

# A somewhat contrived example to demonstrate the use of a multi-principial
# mode (comma-separated clauses) and negation:
# Match files that have _both_ the user and group executable bit set, while
# also _not_ having the other executable bit set.
find -L . -type f -perm -u=x,g=x  \! -perm -o=x

[1] Descrição de -executable partir man findde GNU find 4.4.2:

Corresponde arquivos que são executáveis ​​e diretórios que são pesquisáveis ​​(no sentido de resolução de nome de arquivo). Isso leva em conta as listas de controle de acesso e outros artefatos de permissões que o teste -perm ignora. Este teste faz uso da chamada de sistema access (2), e então pode ser enganado por servidores NFS que fazem mapeamento UID (ou root-squash), uma vez que muitos sistemas implementam access (2) no kernel do cliente e então não podem fazer uso de as informações de mapeamento UID mantidas no servidor. Como esse teste é baseado apenas no resultado da chamada do sistema access (2), não há garantia de que um arquivo para o qual esse teste foi bem-sucedido possa realmente ser executado.

[2] GNU encontrar versões anteriores a 4.5.12 também permitia prefixo +, mas primeiro foi descontinuado e eventualmente removido, porque a combinação +com modos simbólicos provavelmente produz resultados inesperados devido a ser interpretado como uma máscara de permissões exata . Se você (a) executar em uma versão anterior a 4.5.12 e (b) se restringir a octais modos somente, você poderia fugir com o uso +com ambos GNU encontrar e achado BSD, mas não é uma boa idéia.


2
Resposta SO mais abrangente de todos os tempos? ;)
andynormancx

@andynormancx :) Bem, em termos de número absoluto de pontos, posso oferecer este candidato .
mklement0

11

Para ter outra possibilidade 1 de encontrar os arquivos que são executáveis ​​pelo usuário atual:

find . -type f -exec test -x {} \; -print

(o comando de teste aqui é aquele encontrado em PATH, muito provavelmente /usr/bin/test, não o embutido).


1 Use apenas se o -executablesinalizador de findnão estiver disponível! isso é sutilmente diferente da -perm +111solução.


2
Isso funciona, mas é muito lento. Além disso, dependendo do shell, pode ser necessário quebrar ou escapar do marcador de posição do nome do arquivo, como '{}'ou \{\}.
Ionoclast Brigham

1
@ mklement0 isso não encontrará os comandos que são executáveis ​​por mim como -executablefaz ou como meu comando faz.
gniourf_gniourf

1
Obrigado, @gniourf_gniourf - Eu realmente tive alguns equívocos aí. Estou reimprimindo seu outro comentário aqui, porque estou, pelo menos por enquanto, excluindo minha resposta (talvez para ser ressuscitado, SE houver algo recuperável): " nãofind . -type f -perm -u=x é equivalente a : corresponde a todos os arquivos que o usuário pode executar, e estes incluem se eu estiver no grupo adequado ou . Na verdade , encontrarei muitos arquivos que o usuário não pode executar e deixará de encontrar alguns que o usuário pode executar. " -executable-executableg+xo+x-perm -u=x
mklement0

1
@IonoclastBrigham: Embora ter que citar {}seja uma necessidade hipotética (e citar não atrapalha), na prática não é necessário em shells tipo POSIX e csh. Você conhece conchas onde é necessário?
mklement0

4
@IonoclastBrigham: Interessante, obrigado; portanto, em fish, {}deve realmente ser escapado como '{}'ou \{\}. Observe que bash, kshe zshfornecem o mesmo tipo de expansão de chave; no entanto, eles imprimem o token sem aspas {} como está (e, portanto, não há necessidade de escape), porque eles NÃO o consideram uma expressão de chave válida (eles exigem pelo menos 2 tokens ou uma expressão de sequência numérica válida), enquanto fish consideram {}uma chave válida expressão que resulta na string vazia .
mklement0

9

Você pode usar o -executablesinalizador de teste:

-executable
              Matches files which are executable  and  directories  which  are
              searchable  (in  a file name resolution sense).

4
-executable é supostamente uma opção desconhecida.
bem, na verdade

4
Isso seria uma extensão GNU Find? Já que a tag é Unix, não Linux, pelo menos uma extensão GNU precisa ser documentada como tal.
Jonathan Leffler

3
Esta opção não é suportada pelo comando find do BSD encontrado pelo menos no OS X. Esta é uma extensão GNU, mas pode ser suportada por outros tipos de find.
Ionoclast Brigham

FWIW, descobri que não era no sles 10, mas sim no sles> = 11 (fiquei um pouco queimado)
Peter Turner

Observe que, na verdade, isso não inclui todos os exemplos. No meu caso eu tinha um arquivo que possuía e -rw-r-xr-xque -executablenão detecta
Dezza

2

Isso funcionou para mim e pensei em compartilhar ...

find ./ -type f -name "*" -not -name "*.o" -exec sh -c '
    case "$(head -n 1 "$1")" in
      ?ELF*) exit 0;;
      MZ*) exit 0;;
      #!*/ocamlrun*)exit0;;
    esac
exit 1
' sh {} \; -print

13
Apenas mais alguns milhares de caixas e você terá se reinventado file!
tripleee

@tripleee +1. Legal seria esta extensão:find ./ -mime application/x-sharedlib -o -mime application/x-dosexec
Daniel Alder

@Daniel Alder, qual versão do find você usa? Não encontrei a opção -mime em find (GNU findutils) 4.4.2
AjayKumarBasuthkar

@tripleee +1. utilizar 'arquivo' e / 'tipo-mime' é uma boa idéia ou descobrir encontrar a versão que suporte -mime é melhor. Também gostaria de saber se 'arquivo' / 'tipo-mime' tem a opção de filtrar e exibir apenas executáveis.
AjayKumarBasuthkar de

2
find . -executable -type f

realmente não garante que o arquivo seja executável, ele encontrará arquivos com o conjunto de bits de execução. Se você fizer

chmod a+x image.jpg

o achado acima pensará que image.jpg é um executável, mesmo que seja realmente uma imagem jpeg com o conjunto de bits de execução.

Eu geralmente contorno o problema com isto:

find . -type f -executable -exec file {} \; | grep -wE "executable|shared object|ELF|script|a\.out|ASCII text"

Se você quiser que o find realmente imprima informações de cúpula sobre arquivos executáveis, você pode fazer algo assim:

find . -type f -executable -printf "%i.%D %s %m %U %G %C@ %p" 2>/dev/null |while read LINE
do
  NAME=$(awk '{print $NF}' <<< $LINE)
  file -b $NAME |grep -qEw "executable|shared object|ELF|script|a\.out|ASCII text" && echo $LINE
done

No exemplo acima, o nome do caminho completo do arquivo está no último campo e deve refletir onde você o procura com awk "NAME = $ (awk '{print $ NF}' <<< $ LINE)" se o nome do arquivo estiver em outro lugar em a string de saída de localização que você precisa para substituir "NF" pela posição numérica correta. Se o seu separador não for um espaço, você também precisa dizer ao awk qual é o seu separador.


1

É TÃO ridículo que isso não seja super fácil ... muito menos quase impossível . Mãos ao alto, eu reclamo para Apple / Spotlight ...

mdfind 'kMDItemContentType=public.unix-executable'

Pelo menos funciona!


É bom saber sobre mdfindno OSX. Observe que seu comando relata executáveis ​​Unix para todo o sistema . mdfind -onlyin . 'kMDItemContentType=public.unix-executable'limita os resultados à subárvore do diretório atual. Pontos de interesse secundários: limitar a pesquisa a apenas um diretório específico (sem subpastas) aparentemente não é suportado. Aparentemente, links simbólicos para arquivos executáveis ​​nunca são incluídos. Curiosamente, uma vez mdfindencontrado um arquivo para ser executável, posteriormente removendo o bit executável não é recolhido.
mklement0

Acho que encontrei bugs na forma como o Spotlight detecta / não detecta arquivos Unix executáveis; Registrei um bug com a Apple e também em openradar.me/20162683 . Eu encorajo você - e qualquer pessoa interessada nesta funcionalidade - a também registrar um bug em bugreport.apple.com
mklement0

(Desculpe pela enxurrada de comentários; espero que eles estejam corretos agora) mdfind -onlyin . 'kMDItemContentType=public.unix-executable'se comporta como se comporta find . -type f -perm +111 -print. Ou seja, ele encontra arquivos com qualquer conjunto de bits executáveis, o que pode gerar falsos positivos (embora isso possa não ser um problema na prática) - para realmente encontrar apenas arquivos executáveis ​​pelo usuário atual usando BSD find, consulte a resposta de @gniourf_gniourf. Usar uma findsolução baseada em-tem a vantagem de que você também pode encontrar links simbólicos para arquivos executáveis, se desejar (opção -L), o que mdfindaparentemente não é possível.
mklement0

1
@ mklement0 minha resposta evitou enfeites - para tentar acertar o ponto - mas sim, você quase nunca usaria esta forma "sem acabamento". outra opção - não tenho certeza se surgiu - é o bom e velho globbing .. ls /Applications/**/*(*)em sua (minha?) zshconcha
Alex Gray

Obrigado pela zshdica útil - não sabia disso; (parece que você pode , quer corresponder executáveis ( *) ou links simbólicos ( @), mas não ambos, certo?). Quanto ao seu ponto original: Deixe-me reiterar: find . -type f -perm +a=xfará o que seu mdfindcomando faz, ao mesmo tempo que fornece mais flexibilidade. Você pode até reformulá-lo para ser compatível com POSIX.
mklement0

1

Bem, a resposta fácil seria: "seus arquivos executáveis ​​estão nos diretórios contidos em sua variável PATH", mas isso não iria realmente localizar seus executáveis ​​e poderia perder muitos executáveis ​​de qualquer maneira.

Não sei muito sobre mac, mas acho que "mdfind 'kMDItemContentType = public.unix-executable'" pode deixar passar coisas como scripts interpretados

Se estiver tudo bem para você encontrar arquivos com os bits executáveis ​​definidos (independentemente de eles serem realmente executáveis), não há problema em

find . -type f -perm +111 -print

onde suportado, a opção "-executable" fará um filtro adicional olhando para acl e outros artefatos de permissão, mas tecnicamente não é muito diferente de "-pemr +111".

Talvez no futuro o find ofereça suporte a "-magic" e deixe você procurar explicitamente por arquivos com um ID mágico específico ... mas então você teria que especificar todos os formatos executáveis ​​ID mágico.

Não conheço uma maneira fácil e tecnicamente correta de sair do Unix.


1

Portanto, se você realmente deseja encontrar tipos de arquivos executáveis ​​(por exemplo, scripts, binários ELF etc. etc.) e não apenas arquivos com permissão de execução , você provavelmente deseja fazer algo mais parecido com isto (onde o diretório atual. Pode ser substituído por qualquer coisa diretório que você deseja):

 gfind . -type f -exec bash -c '[[ $(file -b "'{}'") == *" executable "* ]] ' \; -print

Ou para aqueles de vocês que não estão usando macports (usuários do Linux) ou de outra forma têm gnu find instalado como você deseja:

 find . -type f -exec bash -c '[[ $(file -b "'{}'") == *" executable "* ]] ' \; -print

Porém, se você estiver no OS X, ele vem com um pequeno utilitário escondido em algum lugar chamado is_exec que basicamente reúne aquele pequeno teste para você, de forma que você possa encurtar a linha de comando se encontrá-lo. Mas desta forma é mais flexível, pois você pode facilmente substituir o teste == pelo teste = ~ e usá-lo para verificar se há propriedades mais complexas, como arquivos de texto simples executáveis ​​ou qualquer outra informação que seu comando de arquivo retornar.


As regras exatas para cotação aqui são muito opacas, então acabo resolvendo por tentativa e erro, mas adoraria ouvir a explicação certa.


0

Eu tive o mesmo problema, e a resposta estava no código-fonte do dmenu : o utilitário stest feito para essa finalidade. Você pode compilar os arquivos 'stest.c' e 'arg.h' e deve funcionar. Há uma página de manual para uso, que coloquei lá por conveniência:

STEST(1)         General Commands Manual         STEST(1)

NAME
       stest - filter a list of files by properties

SYNOPSIS
       stest  [-abcdefghlpqrsuwx]  [-n  file]  [-o  file]
       [file...]

DESCRIPTION
       stest takes a list of files  and  filters  by  the
       files'  properties,  analogous  to test(1).  Files
       which pass all tests are printed to stdout. If  no
       files are given, stest reads files from stdin.

OPTIONS
       -a     Test hidden files.

       -b     Test that files are block specials.

       -c     Test that files are character specials.

       -d     Test that files are directories.

       -e     Test that files exist.

       -f     Test that files are regular files.

       -g     Test  that  files  have  their set-group-ID
              flag set.

       -h     Test that files are symbolic links.

       -l     Test the contents of a directory  given  as
              an argument.

       -n file
              Test that files are newer than file.

       -o file
              Test that files are older than file.

       -p     Test that files are named pipes.

       -q     No  files are printed, only the exit status
              is returned.

       -r     Test that files are readable.

       -s     Test that files are not empty.

       -u     Test that files have their set-user-ID flag
              set.

       -v     Invert  the  sense  of  tests, only failing
              files pass.

       -w     Test that files are writable.

       -x     Test that files are executable.

EXIT STATUS
       0      At least one file passed all tests.

       1      No files passed all tests.

       2      An error occurred.

SEE ALSO
       dmenu(1), test(1)

                        dmenu-4.6                STEST(1)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.