【问题标题】:embedding short python scripts inside a bash script在 bash 脚本中嵌入简短的 python 脚本
【发布时间】: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 文件会增加不必要的开销。

标签: python bash


【解决方案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

【讨论】:

【解决方案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 你能帮忙解决这个问题吗,发布在 stackoverflow 上:stackoverflow.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:你能帮忙解决这个问题吗,发布在 stackoverflow 上:stackoverflow.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 你能帮忙解决这个问题吗,发布在 stackoverflow 上:stackoverflow.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 下面的回答有一个更完整的例子,仅供参考:stackoverflow.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 如果您将所有内容都放在一行中,就像看起来那样,那是行不通的:stackoverflow.com/questions/18660798/…
      猜你喜欢
      • 2023-02-26
      • 2012-05-26
      • 2023-03-07
      • 1970-01-01
      • 2013-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多