在单行命令行中执行多行语句

2025-02-10 08:57:00
admin
原创
49
摘要:问题描述:我正在使用 Python-c执行单行循环,即:python -c "for r in range(10): print 'rob'" 这工作正常。但是,如果我在for循环之前导入模块,就会出现语法错误:python -c "import sys; for r in ra...

问题描述:

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


解决方案 1:

你可以做

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

或者不使用管道:

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

或者

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

或者SilentGhost 的回答或者Crast 的回答。

解决方案 2:

这种风格也可以在 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.

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

EOF 可以替换为任何未出现在此处文档中的行首的标记词(另请参阅 bash 手册页中的此处文档或此处)。

解决方案 3:

问题实际上不在于import语句。问题在于for循环之前的任何内容。或者更具体地说,是内联块之前出现的任何内容。

例如,这些都有效:

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

如果 import 是一个声明的问题,那么这将起作用,但事实并非如此:

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

对于非常基本的示例,您可以将其重写如下:

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

但是,lambda 只能执行表达式,而不能执行语句或多个语句,因此您可能仍然无法完成想要做的事情。但是,在生成器表达式、列表推导、lambda、sys.stdout.write、“map”内置函数和一些创造性的字符串插值之间,您可以执行一些强大的单行代码。

问题是,您想要走多远,以及在什么时候编写一个小.py文件并让您的 makefile 来执行不是更好吗?

解决方案 4:

  • 为了使这个答案也
    适用于 Python 3.xprint ,将其作为函数调用: 在 3.x 中print('foo')有效,而 2.x 也接受print 'foo'。 - 有关包括Windows

在内的跨平台视角,请参阅kxr 的有用答案

bashksh或 中zsh

使用ANSI C 引用字符串( $'...'),它允许使用`
来表示在将字符串传递给 之前扩展为实际换行符的换行符python`:

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

注意和语句`
之间的换行效果。import`for

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

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

请参阅下文有关使用带有嵌入shell 变量引用的(转义序列预处理的)双引号命令字符串的优缺点的讨论。

要安全地使用$'...'字符串:

  • 原始源代码中的双重``实例。

+ `<char>`序列(例如`

本例中的情况,还有常见的情况,例如
)被扩展为$'...'(请参阅 了解man printf`支持的转义符)

  • '实例转义为'


如果必须保持符合 POSIX 标准

printf与命令替换一起使用:

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

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

  • 原始源代码中的双重``实例。

+ `<char>`序列(例如`

本例中所示的序列,以及常见的序列,例如
)被扩展printf(请参阅man printf`以了解支持的转义序列)。

  • 将单引号字符串传递给printf %b并将嵌入的单引号转义为 '''(sic)。

+ 使用单引号可以保护字符串的内容不被 shell*解释*。


    - 也就是说,对于*简短的*Python 脚本(如本例所示),您可以使用双引号字符串将*shell*变量值合并到您的脚本中 - 只要您了解相关的陷阱(参见下一点);例如,shell 扩展`$HOME`为当前用户的主目录。在以下命令中:
    
    
        * `python -c "$(printf %b "import sys

for r in range(10): print('rob is $HOME')")"`

    - 然而,通常首选的方法是通过*参数*从 shell 传递值,并通过`sys.argv`Python 访问它们;上述命令的等效方法是:
    
    
        * `python -c "$(printf %b 'import sys

for r in range(10): print("rob is " + sys.argv[1])')" "$HOME"`

+ 虽然使用*双引号*字符串更*方便*- 它允许您使用未转义的嵌入单引号和嵌入双引号`\"`- 但它也使得字符串受制于 shell 的解释*,*这可能是也可能不是意图;`$`并且```源代码中不适合 shell 的字符可能会导致语法错误或意外更改字符串。


    - 此外,shell 自身``对双引号字符串的处理可能会造成阻碍;例如,要让*Python*生成文字输出`ro`,必须传递`ro\\b`给它;使用`'...'`shell 字符串和*双重* ``实例,我们得到:  
    
    `python -c "$(printf %b 'import sys

print("ro\\bs")')" # ok: 'ros'`

    
    相比之下,这在使用 shell 字符串时*无法*按预期工作`"..."`:  
    
    `python -c "$(printf %b "import sys

print('ro\\bs')")" # !! INCORRECT: 'rs'`

    
    shell 将和*都* 解释为文字,需要大量额外的实例才能达到预期的效果:`""``"\\b"`````  
    
    `python -c "$(printf %b "import sys

print('ro\\\\bs')")"`


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

注意:我在这里关注单行解决方案;xorho 的答案展示了如何使用多行here-document - 但一定要引用分隔符;例如<<'EOF',除非您明确希望 shell 预先扩展字符串(这带有上面提到的注意事项)。


bashksh或 中zsh

将ANSI C 引用字符串( $'...') 与此处字符串( )组合<<<...

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

-明确告诉python从 stdin 读取(默认情况下会这样做)。
-在这种情况下是可选的,但如果您还想将参数传递给脚本,则需要它来消除脚本文件名中的参数歧义:

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

如果必须保持符合 POSIX 标准

使用printf方法如上所述,但使用管道以便通过 stdin 传递其输出:

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

带有论点:

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

解决方案 5:

知道如何修复这个问题吗?

您的问题是由以下事实引起的:Python 语句(用 分隔;)仅允许是“小语句”,它们都是一行。从Python 文档中的语法文件中:

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
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 扩展:

$ 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
...

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

这不太可读:

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

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

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

也许更易读一些,但仍然很丑陋:

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

如果你的 python 中有 's,那你就会有糟糕的经历"

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

不要滥用map或列出理解来获取 for 循环:

' % x), range(10))"

这些都是令人悲伤和糟糕的事。不要做。

解决方案 6:

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

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

rob
rob
...

解决方案 7:

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

工作正常。

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

解决方案 8:

此变体最具可移植性,适用于在 Windows 和类 Unix 系统、Python 2 和 Python 3 上的命令行上放置多行脚本,无需管道:

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

(到目前为止,这里见到的其它例子均没有这样做。)

Windows 上的 Neat 是:

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

类 Unix 系统上的 Bash 的 Neat 功能如下:

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

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

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

用法:

>>> py2cmdline(getcliptext())
python -c "exec('print \'AA    A\'
try:
 for i in 1, 2, 3:
  print i / 0
except:
 print \"\"\"longer
message\"\"\"')"

输入是:

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

解决方案 9:

问题不在于import语句。问题在于控制流语句无法在 Python 解释器命令中内联运行。将该import语句替换为任何其他语句,您都会看到同样的问题。

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

解决方案 10:

如果您的系统符合 POSIX.2 标准,它应该提供以下printf实用程序:

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

zap
rob
rob
rob

解决方案 11:

我并不是一个真正的 Python 爱好者 - 但是我曾经发现过这种语法,忘记从哪里来的了,所以我想记录下来:

如果您使用sys.stdout.write而不是print区别在于,sys.stdout.write将参数作为函数,放在括号中 - 而print没有),那么对于单行命令,您可以颠倒命令和 的顺序for,删除分号,并将命令括在方括号中,即:

python -c "import sys; [sys.stdout.write('rob
') 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()来执行命令,它会在分配后立即执行;然而,后来的检查显示aNone

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:

如果您还记得的话,单行生成器的标准格式是一种括号内的一行“for”循环。这将生成一个“一次性”可迭代对象,该对象只能在一个方向上迭代,并且一旦到达末尾就无法重复使用。

“列表推导”看起来与常规的单行生成器几乎相同,只是常规括号 - ( ) - 被方括号 - [ ] 取代。列表推导的主要优点是生成一个“列表”,而不是“一次性”可迭代对象,以便您可以来回浏览它、添加元素、排序等。

它确实是一个列表 - 只是它的第一个元素在执行时立即变为无:

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]

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

解决方案 12:

single/double quotes以及backslash任何地方:

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

好多了:

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

注意:在某些系统上,可执行文件python适用于 Python 2,可能不可用。可执行文件python3适用于 Python 3。

解决方案 13:

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

  1. 可读性

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

其他答案中没有提供这两个要求,因此这里介绍了在命令行上执行所有操作时读取标准输入的方法:

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
)

解决方案 14:

python -c与三重引号一起使用:

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

解决方案 15:

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

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

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

解决方案 16:

如果您不想接触标准输入并像传递了“python cmdfile.py”一样进行模拟,您可以从 Bash shell 执行以下操作:

python <(printf "word=raw_input('Enter word: ')
import sys
for i in range(5):
    print(word)")

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

解决方案 17:

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

cat somefile.log|python -c "import sys;[line for line in sys.stdin if sys.stdout.write(line*2)]"
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用