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


只需使用Return并在下一行输入它:

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

rob
rob
...

你可以这样做

echo -e "import sys\nfor r in range(10): print 'rob'" | python

或没有管道:

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

Or

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

或者沉默鬼的回答,或者卡斯特的回答。


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

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


问题并不在于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执行不是更好?


如果你的系统是posix .2兼容的,它应该提供printf实用程序:

printf "print 'zap'\nfor r in range(3): print 'rob'" | python

zap
rob
rob
rob

这种风格也可以在makefile中使用(事实上它经常被使用)。

python - <<EOF
import random
for r in range(3): print(random.randint(1, 42))
EOF

或者用硬标签:

python - <<-EOF
    import random
    for r in range(3): print(random.randint(1, 42))
EOF
# Important: Replace the indentation above w/ hard tabs.

在上述情况下,前导制表符也被删除(并且可以实现一些结构化的外观)。

EOF可以容忍没有出现在这里文档中的任何标记词,出现在一行的开头(另请参阅bash手册页中的文档或这里的文档)。


我不是一个真正的大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 -c 'exec("import sys\nfor i in range(10): print \"bob\"")'

更好:

python -c '
import sys
for i in range(10):
  print("bob")
'

注意:在某些系统上,可执行python适用于python 2,可能不可用。可执行的python3是针对python3的。


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

工作很好。

使用“[]”内联for循环。


这个脚本提供了一个类似perl的命令行接口:

Pyliner -在命令行上运行任意Python代码的脚本(Python recipe)


如果你不想触摸标准输入并模拟你已经传递了"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语句中的换行符有三个反斜杠。


还有一个选择。sys.stdout.write返回None,保持列表为空:

cat somefile.log|python -c "import sys;[line for line in sys.stdin if sys.stdout.write(line*2)]"

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

这个变体在Windows和类unix系统(Python 2和Python 3)的命令行上放置多行脚本是最可移植的,没有管道:

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

(到目前为止,这里看到的其他例子都没有这样做。)

Windows上的Neat是:

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

类unix系统上Bash的Neat是:

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

该函数将任何多行脚本转换为可移植的命令行:

def py2cmdline(script):
    exs = 'exec(%r)' % re.sub('\r\n|\r', '\n', script.rstrip())
    print('python -c "%s"' % exs.replace('"', r'\"'))

用法:

>>> py2cmdline(getcliptext())
python -c "exec('print \'AA\tA\'\ntry:\n for i in 1, 2, 3:\n  print i / 0\nexcept:\n print \"\"\"longer\nmessage\"\"\"')"

输入是:

print 'AA    A'
try:
 for i in 1, 2, 3:
  print i / 0
except:
 print """longer
message"""

你知道怎么解决吗?

你的问题是由这样一个事实造成的: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))"

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


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

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

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

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 -c加三引号:

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