Python subprocess.call一个bash别名

jts*_*287 19 python bash subprocess

在工作中有一个列出已完成任务的脚本.这是由其他人编写的,并通过网络托管.我的.bashrc中有一个别名,它调用了这个脚本,有很多标志等等,我想编写一个python脚本,每隔几分钟调用一次这样的别名,这样我就可以打开一个带有更新统计数据的shell.但是,subprocess.call("myAlias")失败了.我对python仍然相当新,我正在努力解决这个问题.

from subprocess import call

def callAlias():
    call("myAlias")

callAlias()
Run Code Online (Sandbox Code Playgroud)

我计划增加更多,但我在第一步遇到障碍.:P

我会发布更多,但有很多敏感的机密内容我必须要小心.对不起,代码模糊,缺少错误输出.

Jon*_*ley 65

如果您需要的别名在〜/ .bashrc中定义,那么它将因以下几个原因而无法运行:

1)你必须给'shell'关键字arg:

subprocess.call('command', shell=True)
Run Code Online (Sandbox Code Playgroud)

否则,您的给定命令用于查找可执行文件,而不是传递给shell,而shell是扩展别名和函数之类的东西.

2)默认情况下,subprocess.call和朋友使用'/ bin/sh'shell.如果这是您要调用的Bash别名,则需要使用'executable'关键字arg告诉子进程使用bash而不是sh:

subprocess.call('command', shell=True, executable='/bin/bash')
Run Code Online (Sandbox Code Playgroud)

3)然而,/ bin/bash不会派生〜/ .bashrc,除非作为'交互'shell启动(带'-i').不幸的是,你无法传递executable ='/ bin/bash -i',它认为整个值是可执行文件的名称.因此,如果您的别名是在用户的正常交互式启动中定义的,例如在.bashrc中,那么您将必须使用以下替代形式来调用命令:

subprocess.call(['/bin/bash', '-i', '-c', command])
# i.e. shell=False (the default)
Run Code Online (Sandbox Code Playgroud)

  • 好答案。[现在推荐](https://docs.python.org/3/library/subprocess.html#older-high-level-api)(并且更容易)使用 subprocess.run(),而不是 subprocess.call( ) (2认同)
  • 如何将上述命令翻译为“subprocess.run”。我尝试了 ```subprocess.run(['echo', "something"], capture_output=True, shell=True, check=True, env=my_env)``` (2认同)
  • 我知道您决定放下自己,感谢您链接到 Triple 的信息丰富的答案。但您确实回答了所提出的问题,即使“更好”的答案是“不要使用别名”,我仍然发现您的答案作为学习练习非常有用。非常感谢! (2认同)

Mar*_*ers 20

您需要将shell关键字设置为True:

call("myAlias", shell=True)
Run Code Online (Sandbox Code Playgroud)

相关文件:

如果shellTrue,则将通过shell执行指定的命令.如果您主要使用Python来提供大多数系统shell提供的增强控制流,并且仍然希望访问其他shell功能(如文件名通配符,shell管道和环境变量扩展),则此功能非常有用.

别名是shell特征(例如,它们由shell定义和解释).

但是,shell(/ bin/sh)是以非交互方式执行的,因此不会读取.profile.bashrc读取文件,并且您的别名可能无法使用.

如果您不愿意将完整的扩展命令用于python脚本,则必须使用$ENV环境变量使shell以其中定义的别名读取文件:

call("myAlias", shell=True, env=dict(ENV='/path/to/aliasfile'))
Run Code Online (Sandbox Code Playgroud)

  • 默认情况下,别名仅在交互式 shell 中启用。 (3认同)
  • 谢谢!这已经是一次接近了,但现在我收到错误 /bin/sh: myAlias: command not found。完全按照我的脚本中的方式运行别名,所以这不是来源问题...... (2认同)

Jam*_*mes 6

我稍微修改了 Jonathan 的理由#2 以使这项工作可行。制作一个/usr/local/bin/interactive_bash包含以下内容的文件

#!/bin/bash
/bin/bash -i "$@"
Run Code Online (Sandbox Code Playgroud)

chmod +x它。然后从Python你可以调用

subprocess.call('my_alias', shell=True, executable='/usr/local/bin/interactive_bash')
Run Code Online (Sandbox Code Playgroud)

  • 有趣的想法,尤其是在你自己的机器上进行黑客攻击时。如果部署到其他人的机器上可能会很棘手。 (2认同)

tri*_*eee 5

The recommended solution is to not use an alias to define functionality which isn't exclusively for interactive use (and even then, shell functions are superior in a number of ways).

Refactor the alias into a standalone script and call it like any other external command.

In more detail, if you have

alias myalias='for x in foo bar baz; do
    frobnicate "$x"; done'
Run Code Online (Sandbox Code Playgroud)

you can improve it so it doesn't pollute your global namespace by turning it into a function

myalias () {
    local x
    for x in foo bar baz; do
        frobnicate "$x"
    done
}
Run Code Online (Sandbox Code Playgroud)

or just save it as /usr/local/bin/myalias and chmod a+x /usr/local/bin/myalias to make it executable for everyone;

#!/bin/sh
for x in foo bar baz; do
    frobnicate "$x"
done
Run Code Online (Sandbox Code Playgroud)

(This runs in a subprocess so x will be gone when the script finishes; so we don't need to make it local.)

(Of course, if frobnicate is at all competently written, maybe you can simplify to just frobnicate foo bar baz as well.)

This is a common FAQ.

  • 您被抢夺了对该答案的投票权。您的答案应该是最高/可接受的答案,而不是我那令人费解的骇客。 (3认同)