在 bash 脚本中嵌入简短的 python 脚本

Posted

技术标签:

【中文标题】在 bash 脚本中嵌入简短的 python 脚本【英文标题】:embedding short python scripts inside a bash script 【发布时间】:2021-12-07 06:21:09 【问题描述】:

我想将短 python 脚本的文本嵌入到 bash 脚本中,例如我的.bash_profile。做这种事情的最佳方法是什么?

到目前为止,我的解决方案是使用-c 选项调用python 解释器,并告诉解释器execstdin 读取的任何内容。从那里,我可以构建类似以下的简单工具,允许我处理文本以在我的交互式提示中使用:

function pyexec() 
    echo "$(/usr/bin/python -c 'import sys; exec sys.stdin.read()')"


function traildirs() 
    pyexec <<END
trail=int('$1:-3')
import os
home = os.path.abspath(os.environ['HOME'])
cwd = os.environ['PWD']
if cwd.startswith(home):
    cwd = cwd.replace(home, '~', 1)
parts = cwd.split('/')
joined = os.path.join(*parts[-trail:])
if len(parts) <= trail and not joined.startswith('~'):
    joined = '/'+joined
print joined
END


export PS1="\h [\$(traildirs 2)] % "

不过,这种方法对我来说有点好笑,我想知道这种方法的替代方法可能是什么。

我的 bash 脚本编写技能非常初级,所以我特别想知道从 bash 解释器的角度来看我是否在做一些愚蠢的事情。

【问题讨论】:

你能更清楚地说出你真正想要做什么吗?据我所知,Python 并不是真正需要的。你可以用 shell 做大部分事情。 @ghostdog74:没有什么比我说的更深刻了;我只是一个比 bash 程序员更好的 python 程序员,而且 IMO python 通常比 bash 更强大。在 python 中实现 bash 脚本中使用的功能可能很方便,并且有时在这样做时不依赖于外部文件。我终于从 tcsh 切换到 bash(15 年后),我正试图将外壳弯曲到我的意愿/偏好。 -1:为什么不简单地创建一个 .py 模块文件?当更好的解决方案是(通常)完全停止使用 shell 时,为什么要强制 Python 进入 shell 脚本? @S.Lott:就我而言,我将 bash 脚本作为 Alfred 命令运行,但需要 Python 的拆分功能。创建 .py 文件会增加不必要的开销。 【参考方案1】:

使用 bash here document 的一个问题是脚本随后会在 stdin 上传递给 Python,因此如果您想使用 Python 脚本作为过滤器,它会变得笨拙。一种替代方法是使用bashprocess substitution,如下所示:

... | python <( echo '
code here
' ) | ...

如果脚本太长,也可以在括号内使用here document,如下所示:

... | python <(
cat << "END"
code here
END
 ) | ...

在脚本内部,您可以像往常一样从/向标准 i/o 读取/写入(例如,sys.stdin.readlines 吞噬所有输入)。

此外,python -c 可以像其他答案中提到的那样使用,但这是我喜欢这样做的方式,以便很好地格式化,同时仍然尊重 Python 的缩进规则 (credits):

read -r -d '' script <<-"EOF"
    code goes here prefixed by hard tab
EOF
python -c "$script"

只需确保此处文档中每一行的第一个字符是硬制表符。如果你必须把它放在一个函数中,那么我使用我在某处看到的以下技巧使其看起来对齐:

function somefunc() 
    read -r -d '' script <<-"----EOF"
        code goes here prefixed by hard tab
----EOF
    python -c "$script"

【讨论】:

为什么 0 票?如果您想在程序中使用 sys.stdin,它是这里唯一正确的答案! 这是迄今为止最好的解决方案!我还要补充一点,您可能希望在第二个示例中引用 END:cat &lt;&lt;'END' 以避免在 HERE 文档中转义 $ 字符和其他特殊字符。 @MichaelGoldshteyn 完成! 有人可以帮我吗。它不起作用#!/system/bin/bash function parse_plex() read -r -d '' script &lt;&lt;-"----EOF" import requests requests.get('https://google.com') ----EOF python -c $script parse_plex 文件“”,第 1 行导入 ^ SyntaxError: invalid syntax @user5507535 您需要在$script 周围加上双引号,例如python -c "$script"。我会更新答案。【参考方案2】:

准备复制粘贴示例:

input="hello"
output=`python <<END
print "$input world";
END`

echo $output

【讨论】:

你能帮忙解决这个问题吗,发布在 *** 上:***.com/questions/68002623/… @AhHatem:你能帮忙解决这个问题吗,发布在 *** 上:***.com/questions/68002623/…【参考方案3】:

试试这个:

#!/bin/bash
a="test"
python -c "print  '$a this is a test'.title()"

【讨论】:

【参考方案4】:

有时使用此处的文档不是一个好主意。另一种选择是使用 python -c:

py_script="
import xml.etree.cElementTree as ET,sys
...
"

python -c "$py_script" arg1 arg2 ...

【讨论】:

既好又简单,让您可以将 python 代码从其余 bash 代码的中间移开。还可以让您的 python 代码从标准输入读取。 @Don Li 你能帮忙解决这个问题吗,发布在 *** 上:***.com/questions/68002623/…【参考方案5】:

如果您使用的是 zsh,您可以使用 zsh 的 join 和 python 标准输入选项 (python -) 将 Python 嵌入到脚本中:

py_cmd=$(j:\n:)"$(f)$(
    # You can also add comments, as long as you balance quotes
    <<<'if var == "quoted text":'
    <<<'  print "great!"')"

catch_output=$(echo $py_cmd | python -)

您可以缩进 Python sn-p,因此在函数内部时它看起来比 EOF&lt;&lt;END 解决方案更好。

【讨论】:

【参考方案6】:

如果你需要在 bash 脚本中使用 python 的输出,你可以这样做:

#!/bin/bash

ASDF="it didn't work"

ASDF=`python <<END
ASDF = 'it worked'
print ASDF
END`

echo $ASDF

【讨论】:

注意命名heredoc标记的方式。当它在您的示例中未引用时,shell 扩展将在 heredoc 字符串中发生。例如,如果您的 python 代码仅包含 print '$SHELL',则输出将是 /bin/bash 或您的外壳恰好是什么。如果将第一行更改为python - &lt;&lt;'END',则输出将为$SHELL。如果您要复制和粘贴现有代码以嵌入到 bash 脚本中,那么您几乎肯定不希望 shell 替换——您希望代码以与未嵌入 bash 脚本时相同的方式运行,对吧?跨度> @desgua:你能帮忙解决这个问题吗,发布在 *** 上:***.com/questions/68002623/…【参考方案7】:

有趣...我现在也想要一个答案 ;-)

他不是在问如何在 bash 脚本中执行 python 代码,而是实际上让 python 设置了环境变量。

把它放在一个 bash 脚本中,并试着让它说“它有效”。

export ASDF="it didn't work"

python <<END
import os
os.environ['ASDF'] = 'it worked'
END

echo $ASDF

问题是 python 在环境的副本中执行。在 python 退出后,不会看到对该环境的任何更改。

如果有解决方案,我也很想看看。

【讨论】:

这并不是我真正想要的,我很确定你不能(直接)从子进程获取环境变量或改变父进程的环境变量(直接)。但是,您可以 eval bash 脚本中的 python 脚本的输出,从而执行任意语句、设置环境变量或执行您可能喜欢的任何其他操作。 @Eric:如果您真的想要答案,请发布您自己的问题。 马特,抱歉...我简单地查看了您的 python 脚本,发现您正在使用 os.environ 做一些事情,并认为这就是您正在做的事情。我的错。 您可以通过结合 bash 变量和 python 输出来管理它。请参阅下面的答案。 @eric.frederich 你能帮忙解决这个问题吗,发布在 *** 上:***.com/questions/68002623/…【参考方案8】:

python 解释器在命令行中接受 - 作为 stdin 的同义词,因此您可以将 pyexec 调用替换为:

python - <<END

参见命令行参考here。

【讨论】:

嗯——我在 python 手册页上进行了文本搜索,但文本 stdin 不在那里。不过,仔细观察,“标准输入”是。呵呵。 同意heredoc方法可以工作。但是有一些事情需要注意:(1)如果heredoc标记(在Ned的例子中为END)出现在Python脚本的第0列,heredoc将提前结束; (2)heredoc 标记的变化(带或不带前导-)会影响制表符和空格是否被保留; (3) 开启变量扩展时 Python 和 bash 之间的语法重叠(heredoc 标记未引用),例如$1 可以合法地出现在 Python 字符串格式说明符中,但如果未引用 heredoc 标记,则将替换为 bash 命令行参数。 注意命名heredoc标记的方式。当它在您的示例中未引用时,shell 扩展将在 heredoc 字符串中发生。例如,如果您的 python 代码仅包含 print '$SHELL',则输出将是 /bin/bash 或您的 shell 恰好是什么。如果将第一行更改为python - &lt;&lt;'END',则输出将为$SHELL。如果您要复制和粘贴现有代码以嵌入到 bash 脚本中,那么您几乎肯定不希望 shell 替换——您希望代码以与未嵌入 bash 脚本时相同的方式运行,对吧?跨度> 一个完整的例子会很好。 Ricardo Cárdenes 下面的回答有一个更完整的例子,仅供参考:***.com/a/2189116/1157440【参考方案9】:

为什么需要使用-c?这对我有用:

python << END
... code ...
END

不需要任何额外的东西。

【讨论】:

为了将输出收集到一个变量中,我做了ABC=$(python &lt;&lt; END ... END) 并且成功了。 如果我们想与 python 通信一个来自 bash 脚本的字符串参数怎么办? 那么你需要-,就像 Ned 的回答一样。参数将跟随破折号。 注意命名heredoc标记的方式。当它在您的示例中未引用时,shell 扩展将在 heredoc 字符串中发生。例如,如果您的 python 代码仅包含 print '$SHELL',则输出将是 /bin/bash 或您的 shell 恰好是什么。如果将第一行更改为python - &lt;&lt;'END',则输出将为$SHELL。如果您要复制和粘贴现有代码以嵌入到 bash 脚本中,那么您几乎肯定不希望 shell 替换——您希望代码以与未嵌入 bash 脚本时相同的方式运行,对吧?跨度> @user3342981 如果您将所有内容都放在一行中,就像看起来那样,那是行不通的:***.com/questions/18660798/…

以上是关于在 bash 脚本中嵌入简短的 python 脚本的主要内容,如果未能解决你的问题,请参考以下文章

如何在 bash 脚本中提示用户进行确认? [复制]

将 Python 脚本的返回值存储在 bash 脚本中

在 Bash 脚本中获取 Python 脚本的退出代码

python 一个简短的脚本,用Python探索Redis pubsub函数

python 刷新HTML文本区域的简短脚本

如何在 Mac 上的 python 脚本中删除 bash 历史记录?