在 Bash 脚本中使用 Python

use*_*877 22 shell scripting bash python

如果我尝试在 bash 脚本中启动 python,脚本将停止运行并且在调用“Python”后不会执行任何命令。在这个简单的例子中,不会打印“TESTPRINT”。似乎脚本刚刚停止。

#!/bin/bash

python

print("TESTPRINT")

Echo
Run Code Online (Sandbox Code Playgroud)

进入Python后如何让脚本继续运行?我相信几年前我在编写了一个首先需要外壳到 Android 手机的脚本后遇到了同样的问题。我不记得当时我是如何修复它的。

Kus*_*nda 46

要从bash脚本运行一组 Python 命令,您必须从您在脚本中创建的文件(Python 脚本)中向 Python 解释器提供要运行的命令,如

#!/bin/bash -e

# Create script as "script.py"
cat >script.py <<'END_SCRIPT'
print("TESTPRINT")
END_SCRIPT

# Run script.py
python script.py

rm script.py
Run Code Online (Sandbox Code Playgroud)

(这会创建一个名为的新文件script.py,如果该文件已经存在,则覆盖该文件,然后指示 Python 运行它;然后将其删除)

...或直接通过某种形式的重定向,例如这里的文档:

#!/bin/bash

python - <<'END_SCRIPT'
print("TESTPRINT")
END_SCRIPT
Run Code Online (Sandbox Code Playgroud)

它所做的是运行python -,它指示 Python 解释器从标准输入读取脚本。然后 shell 将 Python 脚本的文本(END_SCRIPT在 shell 脚本中用 分隔)发送到 Python 进程的标准输入流。

请注意,上面的两段代码略有不同,因为第二个脚本的 Python 进程将其标准输入连接到它正在读取的脚本,而第一个脚本的 Python 进程可以自由地从标准输入读取除脚本之外的数据。如果您的 Python 代码从标准输入读取,这很重要。

Python 还可以通过其-c选项直接从命令行获取一组命令:

#!/bin/bash

python -c 'print("TESTPRINT")'
Run Code Online (Sandbox Code Playgroud)

不能做的是在bash脚本中间“切换到 Python” 。

脚本中的命令一个接bash一个执行,当一个命令正在执行时,脚本本身会等待它终止(如果它不是后台作业)。

这意味着您的原始脚本将以交互模式启动 Python,暂时暂停bash脚本的执行,直到 Python 进程终止。然后脚本将尝试print("TESTPRINT")作为 shell 命令执行。

ssh在脚本中使用类似的问题是类似的问题:

ssh user@server
cd /tmp
ls
Run Code Online (Sandbox Code Playgroud)

(这可能与您几年前所说的类似)。

不会连接到远程系统并在那里运行cdls命令。这将启动远程系统上的交互shell,以及一旦外壳已经终止(放弃控制权交还给脚本),cdls会在本地运行。

相反,要在远程机器上执行命令,请使用

ssh user@server "cd /tmp; ls"
Run Code Online (Sandbox Code Playgroud)

(这是一个蹩脚的例子,但你可能明白这一点)。


下面的示例显示了您实际上可以如何执行您的建议。但是它带有几个警告标签和警告,你永远不应该写这样的代码(因为它被混淆了,因此无法维护,我敢说,非常糟糕)。

python -
print("TESTPRINT")
Run Code Online (Sandbox Code Playgroud)

运行它:

$ sh -s <script.sh
TESTPRINT
Run Code Online (Sandbox Code Playgroud)

这里发生的情况是脚本正在由sh -s. 该-s选项sh(和bash)告诉执行到达了标准输入流的shell脚本外壳。

然后脚本启动python -,它告诉Python运行通过标准输入流传入的任何内容。该流的下一个sh -s内容是 Python 命令,因为它是从Python继承的(因此连接到我们的脚本文本文件)print("TESTPRINT")

然后 Python 解释器将继续从脚本文件读取和执行命令,直到它用完或执行 Python 命令exit()

  • 这就是 JCL(在 IBM 大型机上)和 DCL(Op​​enVMS 和一些 PDP-11 操作系统)等语言的每个命令都以特定字符开头的原因。例如,在 DCL 中,它是 `$`。每一行*不*以`$`开头的行都被假定为程序输入,也就是stdin。这是批处理作业和卡片组的遗产。 (7认同)
  • IBM JCL 仍然需要一个显式指令来读取下一张卡片作为输入。`//SYSIN DD *` 参见 https://www.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.ieab600/iea3b6_Examples_of_SYSIN_DD_statements.htm (2认同)

Akk*_*kko 19

除了 Kusalananda 的答案之外,如果您希望整个脚本由 python 运行,您只需将第一行更改为#!/usr/bin/env python3并像任何普通 shell 脚本一样运行它。这样你就不必记住你必须用哪个解释器运行什么脚本。

  • 更好的是使用`#!/usr/bin/env python3`,这样你就可以使用python3的系统版本了。请参阅 [这个答案为什么](/sf/ask/170065801/ a-pyt)。 (4认同)

小智 9

您也可以尝试使用<<<(Here Strings) 运算符来保存行:

$ python <<< 'print("MyTest")'
MyTest
Run Code Online (Sandbox Code Playgroud)