【问题标题】:Running shell command from python script with \n使用 \n 从 python 脚本运行 shell 命令
【发布时间】:2021-09-26 15:36:36
【问题描述】:

我正在尝试运行 shell 命令

echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -t myimage:latest -

从 jupyter notebook 使用子进程

我已经尝试过代码

p = subprocess.Popen('''echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -t myimage:latest - ''', shell=True)
p.communicate()

还有一些使用 run() 或 call() 的迭代,但每次输出都是

-e '来自忙箱

似乎是换行符 \n 导致了问题。有什么想法可以解决这个问题吗?

【问题讨论】:

  • 创建 sh 脚本文件,将所有行放在那里并从 python 运行。

标签: python docker shell subprocess jupyter


【解决方案1】:

\n 被 Python 解析为文字换行符。您可以通过使用原始字符串来避免这种情况,

p = subprocess.run(
    r'''echo -e 'FROM busybox\nRUN echo "hello world"' | docker build -t myimage:latest - ''',
    shell=True, check=True)

但我建议运行单个进程并传入 Python 的输出;这也是avoids a shell,这通常是可取的。

p = subprocess.run(['docker', 'build', '-t', 'myimage:latest', '-'],
    input='FROM busybox\nRUN echo "hello world"',
    text=True, check=True)

还请注意我们更喜欢subprocess.run() 而不是更原始的subprocess.Popen();正如文档中所建议的,您希望尽可能避免使用此低级功能。使用check=True,我们还注意将任何子进程错误传播到 Python 父进程。

顺便说一句,printfecho -e 更通用,更便携;我通常建议您完全避免使用echo -e

这个ideone demo with nl instead of docker build 演示了变化,巧合地证明了为什么你要避免echo -e,即使你的登录shell 是例如Bash(在这种情况下,您认为应该支持它;但 subprocess 不使用您的登录 shell)。

【讨论】:

  • 您可以添加它以获取原始字符串,必须在该字符串前面添加rr'string goes here'(尽管这是基本的文档信息,应该很容易找到)
  • 感谢您的出色回答。 run() 的第二个解决方案在“输入”中添加了 encode() 成功执行,因为需要一个类似字节的对象,而不是字符串。原始字符串的问题是 \n 作为文字传递给 echo 并且它没有被解释为新行。
  • 明白了,很抱歉,感谢您的编辑!
最近更新 更多