Estou usando Python com -c
para executar um loop de uma linha, ou seja:
$ python -c "for r in range(10): print 'rob'"
Isso funciona bem. No entanto, se eu importar um módulo antes do loop for, recebo um erro de sintaxe:
$ python -c "import sys; for r in range(10): print 'rob'"
File "<string>", line 1
import sys; for r in range(10): print 'rob'
^
SyntaxError: invalid syntax
Alguma idéia de como isso pode ser corrigido?
É importante para mim ter isso como uma linha para que eu possa incluí-lo em um Makefile.
python
shell
command-line
heredoc
Martineau
fonte
fonte
Respostas:
você poderia fazer
ou sem tubos:
ou
ou a resposta do @ SilentGhost / a resposta do @ Crast
fonte
python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
esse estilo também pode ser usado em makefiles (e na verdade é usado com bastante frequência).
ou
neste último caso, os caracteres de tabulação iniciais também são removidos (e algumas perspectivas estruturadas podem ser obtidas)
em vez de EOF pode suportar qualquer palavra de marcador que não apareça no documento aqui no início de uma linha (consulte também aqui documentos na página de manual do bash ou aqui ).
fonte
<<EOF
. Observe, no entanto, que é melhor citar o delimitador - por exemplo,<<'EOF'
- para proteger o conteúdo do documento aqui contra expansões iniciais do shell .O problema não está na declaração de importação, mas em qualquer coisa antes do loop for. Ou, mais especificamente, qualquer coisa que apareça antes de um bloco embutido.
Por exemplo, tudo isso funciona:
Se importar uma declaração fosse um problema, isso funcionaria, mas não:
Para o seu exemplo muito básico, você pode reescrevê-lo da seguinte maneira:
No entanto, as lambdas podem executar apenas expressões, não instruções ou várias instruções, portanto, você ainda pode não conseguir fazer o que deseja. No entanto, entre expressões de gerador, compreensão de lista, lambdas, sys.stdout.write, o "mapa" interno e alguma interpolação criativa de cadeias, você pode executar algumas linhas de comando poderosas.
A questão é: até onde você quer ir e em que momento não é melhor escrever um pequeno
.py
arquivo que seu makefile executa?fonte
- Para que essa resposta funcione também com o Python 3.x ,
print
é chamado como uma função : no 3.x, apenasprint('foo')
funciona, enquanto o 2.x também aceitaprint 'foo'
.- Para uma perspectiva de plataforma cruzada que inclui o Windows , consulte a resposta útil do kxr .
Em
bash
,ksh
ouzsh
:Use uma seqüência de caracteres com citação ANSI C (
$'...'
), que permita usar\n
para representar novas linhas que são expandidas para novas linhas reais antes que a cadeia seja passada parapython
:Observe as instruções
\n
entreimport
efor
para efetuar uma quebra de linha.Para passar valores de variáveis de shell para esse comando, é mais seguro usar argumentos e acessá-los através
sys.argv
do script Python:Veja abaixo uma discussão dos prós e contras do uso de uma cadeia de comandos de aspas duplas ( pré-processada por sequência de escape) com referências de variáveis de shell incorporadas .
Para trabalhar com segurança com
$'...'
cadeias:\
Instâncias duplas no seu código-fonte original .\<char>
- sequências, tais como\n
neste caso, mas também os suspeitos habituais, tais como\t
,\r
,\b
- são expandidos por$'...'
(verman printf
para os escapes de suporte)'
Instâncias de escape como\'
.Se você deve permanecer em conformidade com POSIX :
Use
printf
com uma substituição de comando :Para trabalhar com segurança com esse tipo de string:
\
Instâncias duplas no seu código-fonte original .\<char>
- sequências, tais como\n
neste caso, mas também os suspeitos habituais, tais como\t
,\r
,\b
- são expandidas porprintf
(verman printf
para as sequências de escape suportado).Passe uma sequência de aspas simples para
printf %b
e escape aspas simples incorporadas como'\''
(sic).O uso de aspas simples protege o conteúdo da string da interpretação pelo shell .
Dito isto, para scripts Python curtos (como neste caso), você pode usar uma cadeia de caracteres com aspas duplas para incorporar valores de variáveis de shell em seus scripts - desde que esteja ciente das armadilhas associadas (veja o próximo ponto); por exemplo, o shell se expande
$HOME
para o diretório inicial do usuário atual. no seguinte comando:python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
No entanto, a abordagem geralmente preferida é passar valores do shell por meio de argumentos e acessá-los via
sys.argv
em Python; o equivalente do comando acima é:python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
Embora o uso de uma cadeia de caracteres com aspas duplas seja mais conveniente - ele permite que você use aspas simples incorporadas sem escape e aspas duplas incorporadas, pois
\"
- também torna a string sujeita a interpretação pelo shell , que pode ou não ser a intenção;$
e`
caracteres no código-fonte que não são destinados ao shell podem causar um erro de sintaxe ou alterar a sequência inesperadamente.\
processamento do shell em seqüências de citação dupla pode atrapalhar; por exemplo, para que o Python produza saída literalro\b
, você deve passarro\\b
para ele; com uma'...'
string de shell e instâncias duplicadas\
, obtemos:python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs'
Por outro lado, isso não funciona como planejado com uma
"..."
string de shell:python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
o shell interpreta ambos
"\b"
e"\\b"
como literal\b
, exigindo um número estonteante de\
instâncias adicionais para obter o efeito desejado:python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"
Para passar o código por
stdin
meio de-c
:Nota: Estou focando em soluções de linha única aqui; A resposta do xorho mostra como usar um documento aqui com várias linhas - no entanto, não deixe de citar o delimitador; por exemplo, a
<<'EOF'
menos que você queira explicitamente que o shell expanda a corda na frente (que acompanha as advertências mencionadas acima).Em
bash
,ksh
ouzsh
:Combine uma string (
$'...'
) com citação ANSI C ( ) com uma string here (<<<...
):-
dizpython
explicitamente para ler a partir de stdin (o que faz por padrão).-
é opcional neste caso, mas se você também deseja passar argumentos para os scripts, é necessário desambiguar o argumento de um nome de arquivo de script:Se você deve permanecer compatível com POSIX :
Use
printf
como acima, mas com um pipeline para passar sua saída via stdin:Com um argumento:
fonte
Seu problema é criado pelo fato de que as instruções Python, separadas por
;
, só podem ser "pequenas instruções", que são todas de uma linha. No arquivo de gramática nos documentos do Python :Instruções compostas não podem ser incluídas na mesma linha com outras instruções por ponto e vírgula - portanto, fazer isso com o
-c
sinalizador se torna muito inconveniente.Ao demonstrar o Python em um ambiente de shell bash, acho muito útil incluir instruções compostas. A única maneira simples de fazer isso de forma confiável é com heredocs (uma coisa de shell posix).
Heredocs
Use um heredoc (criado com
<<
) e do Python opção de interface de linha de comando ,-
:Adicionar o
-
depois<<
(o<<-
) permite que você use as guias para recuar (Stackoverflow converte as guias em espaços, por isso recuei 8 espaços para enfatizar isso). As guias principais serão removidas.Você pode fazer isso sem as guias com apenas
<<
:Colocar aspas
EOF
evita a expansão de parâmetros e aritmética . Isso torna o heredoc mais robusto.Bash strings multilinha
Se você usar aspas duplas, obterá expansão do shell:
Para evitar a expansão do shell, use aspas simples:
Observe que precisamos trocar os caracteres de citação nos literais em Python - basicamente não podemos usar o caractere de citação que está sendo interpretado pelo BASH. Podemos alterná-los, como podemos em Python - mas isso já parece bastante confuso, e é por isso que não recomendo:
Crítica da resposta aceita (e outras)
Isso não é muito legível:
Não é muito legível e, além disso, difícil de depurar no caso de um erro:
Talvez um pouco mais legível, mas ainda muito feio:
Você terá um mau momento se estiver
"
no seu python:Não abuse
map
ou liste as compreensões para obter loops for:Tudo isso é triste e ruim. Não os faça.
fonte
bash
,ksh
ouzsh
) é uma solução razoável:python -c $'import sys\nfor r in range(10): print(\'rob\')'
(você só precisa se preocupar em escapar aspas simples (que você pode evitar utilizando aspas duplas) e barras invertidas).basta usar return e digite-o na próxima linha:
fonte
python $(srcdir)/myscript.py
por grande justiça.$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"
Funciona bem. Use "[]" para alinhar seu loop for.
fonte
O problema não está na
import
declaração. O problema é que as instruções de fluxo de controle não funcionam embutidas em um comando python. Substitua essaimport
declaração por qualquer outra e você verá o mesmo problema.Pense nisso: python não pode incorporar tudo. Ele usa indentação para agrupar o controle de fluxo.
fonte
Se o seu sistema for compatível com Posix.2, ele deverá fornecer o
printf
utilitário:fonte
printf %b '...' | python
para maior robustez, porque impede aprintf
interpretação de seqüências como%d
(especificadores de formato) na string de entrada. Além disso, a menos que você queira aplicar explicitamente expansões de shell à sua cadeia de comando Python, o que pode ser confuso, é melhor usar'
(aspas simples) para a citação externa, para evitar as expansões e o processamento de folga que o shell aplica. para cadeias de citação dupla.single/double quotes
e embackslash
todo lugar:Muito melhor:
fonte
(respondeu em 23 de novembro de 2010 às 19:48) Eu não sou realmente um grande Pythoner - mas encontrei essa sintaxe uma vez, esqueci de onde, então pensei em documentá-la:
se você usar em
sys.stdout.write
vez deprint
( a diferença é quesys.stdout.write
aceita argumentos como uma função, entre parênteses -print
e não usa ), então para uma linha, você pode inverter a ordem do comando efor
remover o ponto e vírgula, e colocando o comando entre colchetes, ou seja:Não tenho idéia de como essa sintaxe seria chamada em Python :)
Espero que isto ajude,
Felicidades!
(EDIT terça-feira, 9 de abril, 20:57:30 2013) Bem, acho que finalmente encontrei o significado desses colchetes em uma linha; eles são "compreensões de lista" (aparentemente); observe primeiro no Python 2.7:
Portanto, o comando entre colchetes / parênteses é visto como um "objeto gerador"; se "iterarmos" chamando
next()
- então o comando entre parênteses será executado (observe o "abc" na saída):Se agora usarmos colchetes - observe que não precisamos chamar
next()
para que o comando seja executado, ele será executado imediatamente após a atribuição; no entanto, uma inspeção posterior revela quea
éNone
:Isso não deixa muita informação para procurar, no caso de colchetes - mas me deparei com esta página, que acho que explica:
Dicas e truques para Python - Primeira edição - Tutoriais em Python | Dream.In.Code :
E, de fato, é uma lista - é apenas o primeiro elemento que não se torna assim que é executado:
As compreensões da lista estão documentadas em 5. Estruturas de Dados: 5.1.4. Compreensões de lista - documentação do Python v2.7.4 como "Compreensões de lista fornecem uma maneira concisa de criar listas"; presumivelmente, é aí que a limitada "executabilidade" das listas entra em jogo em uma linha.
Bem, espero não estar muito errado aqui ...
EDIT2: e aqui está uma linha de comando de uma linha com dois for-loops não aninhados; ambos colocados entre colchetes "compreensão da lista":
Observe que a segunda "lista"
b
agora tem dois elementos, já que seu loop for foi executado explicitamente duas vezes; no entanto, o resultado desys.stdout.write()
ambos os casos foi (aparentemente)None
.fonte
Essa variante é mais portátil para colocar scripts de várias linhas na linha de comando no Windows e * nix, py2 / 3, sem pipes:
(Nenhum dos outros exemplos vistos aqui até agora o fez)
Neat no Windows é:
Limpo no bash / * nix é:
Essa função transforma qualquer script de multilinha em um comando-liner portátil:
Uso:
A entrada foi:
fonte
--%
antes do argumento da cadeia de comando.print "path is %%PATH%%"
resp.print "path is $PATH"
geralmente é a opção que se deseja em um script ou linha de comando - a menos que se escape das coisas normalmente para a plataforma. Mesmo com outros idiomas. (A própria sintaxe do Python não sugere regularmente o uso de% e $ 's de maneira competitiva.)$foo
no seu código Python? Se você escapar como\$foo
para o benefício de cartuchos semelhantes ao POSIX,cmd.exe
ainda verá o extra\
. Pode ser raro, mas vale a pena conhecer.Este script fornece uma interface de linha de comando semelhante ao Perl:
Pyliner - Script para executar código Python arbitrário na linha de comando (receita Python)
fonte
Quando eu precisava fazer isso, eu uso
Observe a barra invertida tripla para a nova linha na instrução sys.stdout.write.
fonte
echo -e
, o que é fora do padrão e requerbash
,ksh
ouzsh
, você pode também usar uma$'...'
corda diretamente, o que também simplifica a escapar:python -c $'import sys\nsys.stdout.write("Hello World!\\n")'
Eu queria uma solução com as seguintes propriedades:
Ambos os requisitos não foram fornecidos nas outras respostas, então veja como ler stdin enquanto faz tudo na linha de comando:
fonte
existe mais uma opção, sys.stdout.write retorna None, que mantém a lista vazia
fonte
Se você não quiser tocar em stdin e simular como se tivesse passado "python cmdfile.py", faça o seguinte em um shell bash:
Como você pode ver, ele permite que você use stdin para ler dados de entrada. Internamente, o shell cria o arquivo temporário para o conteúdo do comando de entrada.
fonte
-c "$(...)"
faça o mesmo e seja compatível com POSIX); dar<(...)
um nome à construção: substituição de processo ; também funciona emksh
ezsh
.