python -c 与 python -<< heredoc

python -c vs python -<< heredoc

我正在尝试 运行 Bash 脚本中的一些 Python 代码,所以我想了解以下之间的区别:

#!/bin/bash
#your bash code

python -c "
#your py code
"

python - <<DOC
#your py code
DOC

我上网查了一下,但无法编译与该主题相关的内容。你认为一个比另一个更好吗? 如果您想 return 从 Python 代码块到您的 Bash 脚本的值,那么 heredoc 是唯一的方法吗?

使用 here 文档的主要缺陷是脚本的标准输入将是 here 文档。所以如果你有一个脚本想要处理它的标准输入,python -c 几乎是你唯一的选择。

另一方面,使用 python -c '...' 将单引号绑定到 shell 的需要,因此您只能在 Python 脚本中使用双引号字符串;使用双引号代替 shell 来保护脚本会引入额外的问题(双引号中的字符串进行各种替换,而单引号字符串在 shell 中是文字)。

顺便说一句,请注意您可能还想对 here-doc 定界符进行单引号,否则 Python 脚本会进行类似的替换。

python - <<'____HERE'
print("""Look, we can have double quotes!""")
print('And single quotes! And `back ticks`!')
print("$(and what looks to the shell like process substitutions and $variables!)")
____HERE

作为替代方案,如果您愿意,转义定界符的效果相同 (python - <<\____HERE)

如果您更喜欢使用 python -c '...' 而不必使用双引号转义,您可以先使用此处文档将代码加载到 bash 变量中:

read -r -d '' CMD << '--END'
print ("'quoted'")
--END
python -c "$CMD"

python 代码被逐字加载到 CMD 变量中,无需转义双引号。

如果您正在使用 bash,如果您多应用一些样板文件,就可以避免 heredoc 问题:

python <(cat <<EoF

name = input()
print(f'hello, {name}!')

EoF
)

这将使您可以 运行 嵌入 Python 脚本,而无需放弃标准输入。开销与使用 cmda | cmdb 基本相同。 This technique is known as Process Substitution.

如果想以某种方式验证脚本,我建议您将其转储到一个临时文件中:

#!/bin/bash

temp_file=$(mktemp my_generated_python_script.XXXXXX.py)

cat > $temp_file <<EoF
# embedded python script
EoF

python3 $temp_file && rm $temp_file

如果脚本失败,这将保留脚本 运行。

如何使用 here-docs 输入

包含所有详细信息,但有 Unix 技巧可以解决此限制:

So if you have a script which wants to process its standard input, python -c is pretty much your only option.

这个技巧适用于所有想要从重定向的标准输入(例如,./script.py < myinputs)读取并且接受用户输入的程序:

python - <<'____HERE'
import os

os.dup2(1, 0)
print(input("--> "))
____HERE

运行 这有效:

$ bash heredocpy.sh
--> Hello World!
Hello World!

如果你想得到原始标准输入,运行 os.dup(0) 先。 Here 是一个 real-world 示例。


这是可行的,因为只要 stdout 或 stderr 是 tty,就可以从它们读取以及向它们写入。 (否则,您可以直接打开 /dev/tty。这就是 less 的作用。)

如果您想改为处理来自文件的输入,那也是可能的——您只需要使用一个新的 fd:

文件示例

cat <<'____HERE' > file.txt
With software there are only two possibilites:
either the users control the programme
or the programme controls the users.
____HERE

python - <<'____HERE' 4< file.txt
import os

for line in os.fdopen(4):
  print(line.rstrip().upper())
____HERE

命令示例

不幸的是,管道在这里不起作用 -- 但 process substitution 可以:

python - <<'____HERE' 4< <(fortune)
import os

for line in os.fdopen(4):
  print(line.rstrip().upper())
____HERE