在Bash脚本中嵌入短Python脚本

80 投票
9 回答
81600 浏览
提问于 2025-04-15 18:48

我想在一个bash脚本里嵌入一些简单的python脚本文本,比如说在我的.bash_profile里。请问有什么好的方法可以做到这一点呢?

我目前的解决方案是用-c选项来调用python解释器,并告诉它从stdin读取内容并执行。这样,我就可以构建一些简单的工具,比如下面这个,帮助我处理文本,以便在我的交互式提示符中使用:

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解释器的角度来看,我这样做是不是有点傻。

9 个回答

30

使用 bash 的 here document 有一个问题,就是脚本会通过 stdin 传给 Python,这样如果你想把 Python 脚本当作过滤器来用,就会变得很麻烦。一个替代的方法是使用 bashprocess substitution,像这样:

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

如果脚本太长,你也可以在括号里面使用 here document,像这样:

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

在脚本内部,你可以像平常一样从标准输入/输出读写数据(例如,使用 sys.stdin.readlines 来读取所有输入)。

另外,python -c 也可以用,正如其他回答中提到的,但我喜欢用下面这种方式来格式化代码,同时还遵循 Python 的缩进规则(来源):

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

只要确保 here document 中每一行的第一个字符是一个硬制表符。如果你需要把这个放在一个函数里面,我会用下面这个技巧,让它看起来对齐:

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

为什么你需要使用 -c 呢?对我来说,这样做就可以了:

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

而且不需要额外的东西。

41

Python 解释器在命令行中把 - 当作 stdin 的代名词,这样你就可以用下面的方式替换对 pyexec 的调用:

python - <<END

想了解更多命令行的用法,可以参考 这里

撰写回答