No Python, existe uma maneira portátil e simples de testar se existe um programa executável?
Por simples, quero dizer algo como o whichcomando que seria perfeito. Eu não quero procurar PATH manualmente ou algo que envolva tentar executá-lo com Popen& al e ver se ele falha (é o que estou fazendo agora, mas imagine que seja launchmissiles)
O que há de errado em pesquisar a variável de ambiente PATH? O que você acha que o comando UNIX 'what' faz?
O script which.py ​​do stdlib é uma maneira simples?
@JF - o script which.py ​​incl. com Python depende de 'ls' e alguns dos outros comentários indicam que Piotr estava procurando uma resposta entre plataformas.
— 22468 Jay
@ Jay: Obrigado pelo comentário. Eu tenho o coreutils instalado no Windows, então não notei o arquivo what.py é específico do unix.
Há também which, o módulo de terceiros: code.activestate.com/pypm/which
A maneira mais fácil de pensar:
Editar : amostra de código atualizada para incluir lógica para lidar com o caso em que o argumento fornecido já é um caminho completo para o executável, ou seja, "what / bin / ls". Isso imita o comportamento do comando UNIX 'what'.
Editar : atualizado para usar os.path.isfile () em vez de os.path.exists () por comentários.
Edit : path.strip('"')parece que a coisa errada a fazer aqui. Nem o Windows nem o POSIX parecem incentivar os itens PATH citados.
Obrigado Jay, aceito sua resposta, embora, para mim, responda minha pergunta pelo negativo. Nenhuma função existe nas bibliotecas, eu apenas tenho que escrevê-la (admito que minha formulação não foi clara o suficiente no fato de eu saber o que faz).
Jay, se você completar sua resposta de acordo com a minha (para ter 'w' completo), para que eu possa remover a minha.
Para alguns sistemas operacionais, pode ser necessário adicionar a extensão do executável. Por exemplo, no Ubuntu eu posso escrever qual ("scp"), mas no Windows, eu preciso escrever qual ("scp.exe").
— 9309 waffleman
Eu sugiro alterar "os.path.exists" para "os.path.isfile". Caso contrário, no Unix, isso pode corresponder falsamente a um diretório com o conjunto de bits + x. Também acho útil adicionar isso ao topo da função: import sys; se sys.platform == "win32" e não program.endswith (". exe"): programa + = ".exe". Dessa forma, no Windows, você pode consultar "calc" ou "calc.exe", como faria em uma janela do cmd.
— 22411 Kevin Ivarsen
@KevinIvarsen A melhor opção seria looping através dos valores do PATHEXTenv var porque commandé tão válida quanto command.comcomo é scriptvsscript.bat
Eu sei que esta é uma pergunta antiga, mas você pode usar distutils.spawn.find_executable. Isso foi documentado desde o python 2.4 e existe desde o python 1.6.
Além disso, o Python 3.3 agora oferece shutil.which().
Em win32, a distutils.spawn.find_executableimplementação procura apenas em .exevez de usar a lista de extensões para procurar a configuração %PATHEXT%. Isso não é ótimo, mas pode funcionar para todos os casos de que alguém precisa.
exemplo de uso:from distutils import spawn php_path = spawn.find_executable("php")
Aparentemente, distutils.spawnnão está disponível de maneira confiável: com minha instalação do sistema (/ usr / bin / python) do Python 2.7.6 no OS X 10.10, recebo AttributeError: 'module' object has no attribute 'spawn':, embora estranhamente funcione na mesma máquina com a mesma versão do Python, mas em uma instalação virtualenv.
— Josh Kupershmidt 10/0316
@JoshKupershmidt, certifique-se de import distutils.spawnseguir a from distutils import spawnsintaxe, e não apenas import distutils. Caso contrário, pode não estar acessível e você obterá o que foi mencionado acima, AttributeErrormesmo que esteja lá.
O Python 3.3 agora oferece shutil.which () .
Para python 3.2 e versões anteriores:
Esta é uma linha da resposta de Jay , também aqui como uma função lambda:
Ou, por último, recuado como uma função:
Para python 3.3 e posterior:
Como uma linha de resposta de Jan-Philip Gehrcke :
Como um def:
a versão "recuado como uma função" usa a variável xonde deveria estarcmd
você também deve adicionar um teste para ver se os.path.join(path, cmd)é um arquivo, não? Afinal, diretórios também pode ter o conjunto de bits executável ...
@MestreLion Parece um possível caso, você se importaria de confirmar esse comportamento e atualizar esta resposta? Fico feliz em mudar este post para um wiki da comunidade, se isso ajudar.
@ ThorSummoner: Eu confirmei, e realmente exige o teste para o arquivo. Um teste simples:mkdir -p -- "$HOME"/bin/dummy && PATH="$PATH":"$HOME"/bin && python -c 'import os; print any(os.access(os.path.join(path, "dummy"), os.X_OK) for path in os.environ["PATH"].split(os.pathsep))' && rmdir -- "$HOME"/bin/dummy
Adicionando um simples and os.path.isfile(...)para os lugares apropriados é suficiente para correção
Lembre-se de especificar a extensão do arquivo no Windows. Caso contrário, você precisará escrever um tópico muito complicado is_exepara o Windows usando PATHEXTa variável de ambiente. Você pode apenas querer usar o FindPath .
OTOH, por que você está se preocupando em procurar o executável? O sistema operacional fará isso por você como parte da popenchamada e gerará uma exceção se o executável não for encontrado. Tudo o que você precisa fazer é capturar a exceção correta para o SO fornecido. Observe que, no Windows, subprocess.Popen(exe, shell=True)falhará silenciosamente se exenão for encontrado.
Incorporando PATHEXTna implementação acima de which(na resposta de Jay):
Foi corrigido um erro na resposta aceita; sinta que esta resposta deve estar no topo.
— NiTe Luo 19/09/17
o uso inteligente de yieldnos ext_candidates, deu-me uma melhor compreensão de como que as obras de palavra-chave
Para plataformas * nix (Linux e OS X)
Isso parece estar funcionando para mim:
Editado para funcionar no Linux, graças a Mestreion
O que estamos fazendo aqui é usar o comando embutido typee verificar o código de saída. Se não houver esse comando, typesairá com 1 (ou um código de status diferente de zero).
A parte sobre stdout e stderr é apenas para silenciar a saída do typecomando, pois estamos interessados ​​apenas no código de status de saída.
Tem certeza de que isso funciona? É uma abordagem muito boa, mas typeé um shell embutido, não um arquivo executável, portanto subprocess.call()falha aqui.
Você já tentou ou está apenas teorizando? Funciona de qualquer maneira no meu mac.
— hasen 23/05
Eu tentei no Ubuntu 12.04, lança OSError: [Errno 2] No such file or directory. Talvez no Mac typeé um comando real
Depois de um monte de testes, eu descobri como corrigir: add shell=Truee substituir ["type", cmd]por"type " + cmd
Atenção: verifique se a variável "cmd" contém dados válidos. Se vier de uma fonte externa, um bandido poderá fornecer "ls; rm -rf /". Eu acho que a solução em python (sem subprocesso) é muito melhor. Próximo ponto: se você chamar esse método frequentemente, a solução do subprocesso será muito mais lenta, pois muitos processos precisam ser gerados.
Veja o módulo os.path para algumas funções úteis nos nomes de caminho. Para verificar se um arquivo existente é executável, use os.access (caminho, modo) , com o modo os.X_OK.
Valor a incluir no parâmetro mode de access () para determinar se o caminho pode ser executado.
Edição: As which()implementações sugeridas estão faltando uma pista - usando os.path.join()para criar nomes de arquivos completos.
Obrigado, gimel, então basicamente tenho a minha resposta: não existe essa função, devo fazê-la manualmente.
Não use os.access. A função de acesso foi projetada para programas suid.
Com base em que é mais fácil pedir perdão do que permissão, eu apenas tentaria usá-lo e capturar o erro (neste caso, OSError - verifiquei se o arquivo não existe e o arquivo não é executável e ambos fornecem o OSError).
Ajuda se o executável tem algo como um --versionsinalizador que é um rápido não funcionamento.
Essa não é uma solução geral, mas será a maneira mais fácil para muitos casos de uso - aqueles em que o código precisa procurar um único executável conhecido.
É muito perigoso até mesmo chamar --versionum programa chamado launchmissiles!
+1, eu gosto dessa abordagem. O EAFP é uma regra de ouro do Python. Exceto, talvez, a configuração da interface do usuário, por que você gostaria de saber se launchmissiesexiste, a menos que queira lançar mísseis? Melhor para executá-lo e agir de acordo com status de saída / exceções
O problema com esse método é que a saída é impressa no console. Se você usar tubos e shell = True, então o OSError nunca é levantada
No macOS, você também tem executáveis ​​stub, por exemplo, gitque provavelmente não deseja executar às cegas.
Sei que estou sendo um pouco necromante aqui, mas me deparei com essa pergunta e a solução aceita não funcionou para mim em todos os casos. Achei que seria útil enviar de qualquer maneira. Em particular, a detecção do modo "executável" e o requisito de fornecer a extensão do arquivo. Além disso, o python3.3 shutil.which(usa PATHEXT) e o python2.4 + distutils.spawn.find_executable(apenas tenta adicionar '.exe') funcionam apenas em um subconjunto de casos.
Então, escrevi uma versão "super" (com base na resposta aceita e na PATHEXTsugestão de Suraj). Esta versão whichfaz a tarefa um pouco mais detalhadamente e tenta primeiro uma série de técnicas de "fase larga" em primeiro lugar e, eventualmente, tenta pesquisas mais refinadas no PATHespaço:
A solução aceita não funcionou para mim neste caso, uma vez que havia arquivos como meld.1, meld.ico, meld.doap, etc, também no diretório, um dos quais foram devolvidos em vez (presumivelmente desde lexicographically primeiro) porque o teste executável na resposta aceita foi incompleta e dando falso-positivo.
O melhor exemplo deve ser o módulo bulit-in python shutil.which () no Python 3. O link é https://hg.python.org/cpython/file/default/Lib/shutil.py
— liuyix
Encontrei algo no StackOverflow que resolveu o problema para mim. Isso funciona desde que o executável tenha uma opção (como --help ou --version) que produz algo e retorna um status de saída igual a zero. Consulte Suprimir saída em chamadas do Python para executáveis - o "resultado" no final do trecho de código nesta resposta será zero se o executável estiver no caminho, caso contrário, é mais provável que seja 1.
Isso parece bastante simples e funciona tanto em python 2 quanto em 3
Desculpe Jaap, mas esta solução só funciona quando o executável não chama um código de saída 1 se for chamado incorretamente. Então, por exemplo, funcionará para "dir" e "ls", mas se você executar contra algo que exija configuração, ele será interrompido mesmo que o executável esteja lá.
O que você quer dizer exatamente com "exigir configuração"? Por si só, 'what', na verdade, não executa nada, mas apenas verifica o PATH quanto à existência de um executável com esse nome (man what).
— 26615
Ohh, então você está usando "what" para encontrar o executável. Então, isso só funciona para Linux / Unix?
Use command -v executableou type executablepara ser universal. Há casos em que nos Macs não retorna os resultados esperados.
Uma pergunta importante é " Por que você precisa testar se existe um executável?" Talvez você não? ;-)
Recentemente, eu precisava dessa funcionalidade para iniciar o visualizador de arquivos PNG. Eu queria interagir com alguns espectadores predefinidos e executar o primeiro que existe. Felizmente, me deparei os.startfile. É muito melhor! Simples, portátil e usa o visualizador padrão no sistema:
Atualização: Eu estava errado em os.startfileser portátil ... É apenas o Windows. No Mac, você deve executar o opencomando. E xdg_openno Unix. Há um problema de Python ao adicionar suporte para Mac e Unix os.startfile.
Você pode tentar a biblioteca externa chamada "sh" ( http://amoffat.github.io/sh/ ).
— jung rhew
Adicionado suporte ao windows
você pode dizer se existe um arquivo com o módulo os. um executável em particular parece bastante portável, considerando que muitas coisas são executáveis ​​no nix que não estão no Windows e vice-versa.
Parece que a escolha óbvia é "what", analisando os resultados via popen, mas você pode simular isso usando a classe os. No pseudopython, ficaria assim:
Eu teria cuidado ao executar um comando "what" usando os.exec ou algo parecido. Não apenas é frequentemente lento (se o desempenho é algum tipo de preocupação), mas se você estiver usando uma variável como parte de sua cadeia de exec, a segurança se tornará uma preocupação. Alguém poderia se infiltrar em um "rm -rf /".
Qual, como estaríamos usando a função os.popen para executar um comando criado pelo programa, na verdade não se aplica, não?
Obrigado, mas não tenho certeza se 'qual' existe no Windows e nos gostos. Eu queria essencialmente saber se existe algo chique na lib padrão
— Piotr Lesnicki 18/12/08
Nas instalações padrão do Windows, ainda não há whichcomando; existe uma versão do UnxUtils, mas você deve saber / especificar a extensão, caso contrário, o programa não será encontrado.
Então, basicamente, você deseja encontrar um arquivo no sistema de arquivos montado (não necessariamente nos diretórios PATH) e verificar se é executável. Isso se traduz no seguinte plano:
enumere todos os arquivos em sistemas de arquivos montados localmente
corresponder resultados com padrão de nome
para cada arquivo encontrado, verifique se é executável
Eu diria que fazer isso de maneira portátil exigirá muito poder e tempo de computação. É realmente o que você precisa?
Existe um script what.py em uma distribuição padrão do Python (por exemplo, no Windows '\PythonXX\Tools\Scripts\which.py').
EDIT: which.pydepende, lsportanto, não é multiplataforma.
Nenhum dos exemplos anteriores funciona em todas as plataformas. Geralmente eles não funcionam no Windows, porque você pode executar sem a extensão do arquivo e registrar uma nova extensão. Por exemplo, no Windows, se o python estiver bem instalado, basta executar 'file.py' e ele funcionará.
A única solução válida e portátil que eu tinha era executar o comando e ver o código de erro. Qualquer executável decente deve ter um conjunto de parâmetros de chamada que não farão nada.
Usando a biblioteca de malhas python:
— frodopwns
Esta é uma sugestão muito ruim . Você está literalmente fazendo com que o programa dependa da biblioteca de execução remota para gerar um programa local (o que o Python stdlib pode fazer com facilidade) e, além disso, depende do which(1)que não está presente em todos os sistemas.