我使用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中。


当前回答

问题不在于import语句。问题是控制流语句不能内联在Python解释器命令中工作。将该import语句替换为任何其他语句,您将看到相同的问题。

想想看:Python不可能内联所有东西。它使用缩进来分组控制流。

其他回答

我不是一个真正的大python -但我发现这个语法一次,忘记从哪里来的,所以我想我应该记录它:

如果你使用sys.stdout.write而不是print(区别在于,sys.stdout.write接受圆括号内的函数参数-而print不接受),那么对于一行程序,你可以将命令和for的顺序颠倒,删除分号,并将命令括在方括号中,即:

python -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

我不知道这个语法在Python中是如何调用的:)


一行中的方括号是“列表推导式”;在Python 2.7中注意这一点:

STR=abc
echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); print a"

输出:

<generator object <genexpr> at 0xb771461c>

因此,圆括号/圆括号中的命令被视为“生成器对象”;如果我们通过调用next()来“迭代”它,那么括号内的命令将被执行(注意输出中的“abc”):

echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); a.next() ; print a"

输出:

abc
<generator object <genexpr> at 0xb777b734>

如果我们现在使用方括号——注意我们不需要调用next()来执行命令,它会在赋值时立即执行;然而,后来的检查发现a是None:

echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; print a"

输出:

abc
[None]

这并没有留下太多的信息去寻找——对于方括号的情况——但我偶然发现了这一页,我认为它解释了:

Python技巧和技巧-第一版- Python教程| Dream.In.Code:

If you recall, the standard format of a single line generator is a kind of one line 'for' loop inside brackets. This will produce a 'one-shot' iterable object which is an object you can iterate over in only one direction and which you can't re-use once you reach the end. A 'list comprehension' looks almost the same as a regular one-line generator, except that the regular brackets - ( ) - are replaced by square brackets - [ ]. The major advantage of alist comprehension is that produces a 'list', rather than a 'one-shot' iterable object, so that you can go back and forth through it, add elements, sort, etc.

实际上它是一个列表——只是它的第一个元素在执行时变成了none:

echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin].__class__"

输出:

abc
<type 'list'>

echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin][0]"

输出:

abc
None

列表推导式在5中另有说明。数据结构:5.1.4。列表推导式——Python v2.7.4文档“列表推导式提供了一种简洁的创建列表的方法”;据推测,这就是列表的有限“可执行性”在一行程序中发挥作用的地方。

好吧,希望我没有说得太离谱……

这里有一个单行命令行,包含两个非嵌套的for循环;两者都包含在“列表理解”方括号内:

echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; b=[sys.stdout.write(str(x)) for x in range(2)] ; print a ; print b"

输出:

abc
01[None]
[None, None]

注意,第二个“列表”b现在有两个元素,因为它的for循环显式地运行了两次;然而,sys.stdout.write()在这两种情况下的结果(显然)都是None。

-使用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'

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

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

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

我想要一个具有以下属性的解决方案:

可读的 读取标准输入以处理其他工具的输出

这两个要求在其他答案中都没有提供,所以下面是如何在命令行上执行所有操作时读取标准输入:

grep special_string -r | sort | python3 <(cat <<EOF
import sys
for line in sys.stdin:
    tokens = line.split()
    if len(tokens) == 4:
        print("%-45s %7.3f    %s    %s" % (tokens[0], float(tokens[1]), tokens[2], tokens[3]))
EOF
)

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

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

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