我使用Python和-c来执行一行循环,即:

python -c "for r in range(10): print 'rob'"

这很好。但是,如果我在for循环之前导入一个模块,就会得到一个语法错误:

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

如何解决这个问题?

对我来说,将它作为一行程序很重要,这样我就可以将它包含在Makefile中。


当前回答

你知道怎么解决吗?

你的问题是由这样一个事实造成的:Python语句,用;分隔,只允许是“小语句”,它们都是一行程序。来自Python文档中的语法文件:

标准时间: simple_stmt |compound_stmt simple_stmt: small_stmt (“;”small_stmt)* [“;”]换行符 small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt |global_stmt |nonlocal_stmt |assert_stmt)

复合语句不能通过分号与其他语句包含在同一行中——因此使用-c标志来做到这一点非常不方便。

在bash shell环境中演示Python时,我发现包含复合语句非常有用。唯一可靠的简单方法是使用heredocs (posix shell的东西)。

赫里多克斯

使用heredoc(使用<<创建)和Python的命令行接口选项,-:

$ python - <<-"EOF"
        import sys                    # 1 tab indent
        for r in range(10):           # 1 tab indent
            print('rob')              # 1 tab indent and 4 spaces
EOF

在<<之后添加-(<<-)允许您使用制表符缩进(Stackoverflow将制表符转换为空格,因此我缩进了8个空格以强调这一点)。前面的制表符将被剥离。

你可以在没有标签的情况下使用<<:

$ python - << "EOF"
import sys
for r in range(10):
    print('rob')
EOF

在EOF周围加上引号可以防止参数和算术扩展。这使得heredoc更加健壮。

Bash多行字符串

如果你使用双引号,你会得到shell- expand:

$ python -c "
> import sys
> for p in '$PATH'.split(':'):
>     print(p)
> "
/usr/sbin
/usr/bin
/sbin
/bin
...

为了避免shell扩展,请使用单引号:

$ python -c '
> import sys
> for p in "$PATH".split(":"):
>     print(p)
> '
$PATH

注意,我们需要在Python中对字面量交换引号字符-我们基本上不能使用由BASH解释的引号字符。我们可以交替使用它们,就像在Python中一样——但这看起来已经很混乱了,这就是为什么我不建议这样做:

$ python -c '
import sys
for p in "'"$PATH"'".split(":"):
    print(p)
'
/usr/sbin
/usr/bin
/sbin
/bin
...

对已接受答案(和其他答案)的批评

这不是很好读:

Echo -e "import sys\nfor rin range(10): print 'rob'" | python

可读性不强,而且在出现错误的情况下很难调试:

Python -c "exec(\"import sys\\nfor rin range(10): print 'rob'\")"

也许可读性更强一些,但仍然很难看:

(echo "import sys";Echo "for rin range(10): print 'rob'") | python

如果你的python里有",你就会过得很糟糕:

$ python -c "import sys . > for rin range(10): print 'rob'"

不要滥用map或list推导式来获取for循环:

import sys;Map (lambda x: sys.stdout。Write ('rob%d\n' % x), range(10))"

这些都是悲伤而糟糕的。不要这样做。

其他回答

如果你不想触摸标准输入并模拟你已经传递了"python cmdfile.py",你可以在Bash shell中执行以下操作:

python <(printf "word=raw_input('Enter word: ')\nimport sys\nfor i in range(5):\n    print(word)")

如您所见,它允许您使用标准输入读取输入数据。shell在内部为输入命令内容创建临时文件。

当我需要这样做时,我使用:

python -c "$(echo -e "import sys\nsys.stdout.write('Hello, World!\\\n')")"

注意sys.stdout.write语句中的换行符有三个反斜杠。

使用python -c加三引号:

python -c """
import os
os.system('pwd')
os.system('ls -l')
print('Hello, World!')
for _ in range(5):
    print(_)
"""

问题并不在于import语句。它是在for循环之前的任何东西。或者更具体地说,出现在内联块之前的任何东西。

例如,这些都是有效的:

python -c "import sys; print 'rob'"
python -c "import sys; sys.stdout.write('rob\n')"

如果import是一个语句是一个问题,这将工作,但它不是:

python -c "__import__('sys'); for r in range(10): print 'rob'"

对于最基本的例子,你可以这样写:

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

然而,lambdas只能执行表达式,而不能执行语句或多条语句,因此您可能仍然无法执行您想要执行的事情。然而,在生成器表达式、列表理解、lambdas、sys.stdout之间。写,“映射”内置,和一些创造性的字符串插值,你可以做一些强大的一行程序。

问题是,您想要走多远,以及在什么情况下编写一个小的.py文件而让makefile执行不是更好?

-使用Python 3使这个答案生效。X以及,print被称为一个函数:在3。X,只有print('foo')可以工作,而2。X也接受打印'foo'。 -关于跨平台(包括Windows)的观点,请参阅kxr的有用答案。

在bash、ksh或zsh中:

使用ANSI c引号字符串($'…'),它允许使用\n表示在字符串传递给python之前展开为实际换行的换行:

python -c $'import sys\nfor r in range(10): print("rob")'

注意import语句和for语句之间的\n可以产生换行。

要将shell变量值传递给这样的命令,最安全的方法是使用参数并通过sys. js访问它们。Python脚本中的argv:

name='rob' # value to pass to the Python script
python -c $'import sys\nfor r in range(10): print(sys.argv[1])' "$name"

关于使用(转义序列预处理)双引号命令字符串与嵌入的shell变量引用的优缺点,请参见下面的讨论。

使用$'安全工作…的字符串:

在原始源代码中使用双实例。 \<char>序列-例如本例中的\n,但也有常见的嫌疑,例如\t, \r, \b -被$'…’(参见man printf了解支持的转义) 转义“实例为\”。


如果你必须保持posix兼容:

使用printf替换命令:

python -c "$(printf %b 'import sys\nfor r in range(10): print("rob")')"

要安全地使用这种类型的字符串:

Double \ instances in your original source code. \<char> sequences - such as \n in this case, but also the usual suspects such as \t, \r, \b - are expanded by printf (see man printf for the supported escape sequences). Pass a single-quoted string to printf %b and escape embedded single quotes as '\'' (sic). Using single quotes protects the string's contents from interpretation by the shell. That said, for short Python scripts (as in this case) you can use a double-quoted string to incorporate shell variable values into your scripts - as long as you're aware of the associated pitfalls (see next point); e.g., the shell expands $HOME to the current user's home dir. in the following command: python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")" However, the generally preferred approach is to pass values from the shell via arguments, and access them via sys.argv in Python; the equivalent of the above command is: python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME" While using a double-quoted string is more convenient - it allows you to use embedded single quotes unescaped and embedded double quotes as \" - it also makes the string subject to interpretation by the shell, which may or may not be the intent; $ and ` characters in your source code that are not meant for the shell may cause a syntax error or alter the string unexpectedly. Additionally, the shell's own \ processing in double-quoted strings can get in the way; for instance, to get Python to produce literal output ro\b, you must pass ro\\b to it; with a '...' shell string and doubled \ instances, we get: python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs' By contrast, this does not work as intended with a "..." shell string: python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs' The shell interprets both "\b" and "\\b" as literal \b, requiring a dizzying number of additional \ instances to achieve the desired effect: python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"


通过stdin而不是-c来传递代码:

注意:这里我关注的是单线解决方案;Xorho的回答展示了如何使用多行here-document -但一定要引用分隔符;例如,<<'EOF',除非你明确地想让shell在前面展开字符串(这与上面提到的注意事项一起出现)。


在bash、ksh或zsh中:

将ANSI c引号字符串($'…')与here字符串(<<<…)组合:

python - <<<$'import sys\nfor r in range(10): print("rob")'

-告诉python显式地从stdin读取(默认情况下)。 -在这种情况下是可选的,但如果你还想向脚本传递参数,你确实需要它来消除脚本文件名的参数歧义:

python - 'rob' <<<$'import sys\nfor r in range(10): print(sys.argv[1])'

如果你必须保持posix兼容:

像上面一样使用printf,但是使用管道,以便通过stdin传递输出:

printf %b 'import sys\nfor r in range(10): print("rob")' | python

带论点:

printf %b 'import sys\nfor r in range(10): print(sys.argv[1])' | python - 'rob'