Python subprocess.call 一个 bash 别名

Posted

技术标签:

【中文标题】Python subprocess.call 一个 bash 别名【英文标题】:Python subprocess.call a bash alias 【发布时间】:2012-08-17 03:40:09 【问题描述】:

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

from subprocess import call

def callAlias():
    call("myAlias")

callAlias()

我也计划添加更多,但我在第一步中遇到了障碍。 :P

我会发布更多信息,但我必须小心处理很多敏感的机密内容。抱歉,代码含糊不清,缺少错误输出。

【问题讨论】:

在这种情况下,最好将脚本名称和所有参数放在字符串列表中并将其用于您的call,而不是依赖可能或可能不存在。 避免使用别名是解决此问题的最简单和常见的解决方案。将别名内联到您的 call() 参数中,或者将别名转换为 call() 可以调用的脚本。 【参考方案1】:

更新:感谢大家对这个 hack 解决问题的支持,我很高兴它很有用。但是一个更好的答案是三人组的,在页面的下方徘徊......

如果您需要的别名是在 ~/.bashrc 中定义的,那么由于以下几个原因它不会运行:

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

subprocess.call('command', shell=True)

否则,您给定的命令将用于查找可执行文件,而不是传递给 shell,它是扩展别名和函数等内容的 shell。

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

subprocess.call('command', shell=True, executable='/bin/bash')

3) 但是,/bin/bash 不会获取 ~/.bashrc,除非作为“交互式”shell(使用“-i”)启动。不幸的是,您不能传递 executable='/bin/bash -i ',因为它认为整个值是可执行文件的名称。因此,如果您的别名是在用户的正常交互式启动中定义的,例如在 .bashrc 中,那么您必须使用这种替代形式调用命令:

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

【讨论】:

好答案。 now recommended(更容易)使用 subprocess.run(),而不是 subprocess.call() 如何将上述命令翻译成subprocess.run。我试过subprocess.run(['echo', "something"], capture_output=True, shell=True, check=True, env=my_env)【参考方案2】:

我稍微修改了乔纳森的理由 #2 来完成这项工作。制作一个包含

/usr/local/bin/interactive_bash文件
#!/bin/bash
/bin/bash -i "$@"

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

subprocess.call('my_alias', shell=True, executable='/usr/local/bin/interactive_bash')

【讨论】:

有趣的想法,尤其是在你自己的机器上乱搞的时候。但是,如果部署到其他人的机器上可能会很棘手。 是的,这可能不是我在生产中使用的感觉很好:) "$@" 周围的引用不见了。【参考方案3】:

推荐的解决方案是不要使用别名来定义不是专有用于交互使用的功能(即使这样,shell 函数在许多方式)。

将别名重构为独立脚本,并像任何其他外部命令一样调用它。

如果你有更详细的说明

alias myalias='for x in foo bar baz; do
    frobnicate "$x"; done'

你可以改进它,这样它就不会通过将它变成一个函数来污染你的全局命名空间

myalias () 
    local x
    for x in foo bar baz; do
        frobnicate "$x"
    done

或将其另存为 /usr/local/bin/myaliaschmod a+x /usr/local/bin/myalias 以使其对所有人都可执行;

#!/bin/sh
for x in foo bar baz; do
    frobnicate "$x"
done

(这在子进程中运行,因此脚本完成后x 将消失;因此我们不需要将其设为local。)

(当然,如果frobnicate 写得很好,也许你也可以简化为frobnicate foo bar baz。)

这是一个常见的常见问题解答。

【讨论】:

您在此答案的投票中被抢了。你的应该是最佳/接受的答案,而不是我可怕的令人费解的黑客攻击。 @JonathanHartley 感谢您的支持和评论 (-: 有时你必须使用别名。就像当你想从另一个 + 许多其他情况下运行一些快速安装的应用程序时...... @rubmz 这听起来不像你需要一个别名。事实上,这听起来像是另一种情况,别名不如函数、shell 包装器或PATH 调整。 说你想以编程方式启动一个现有的应用程序。该应用程序可以安装在操作系统中的任何位置,但它有(并且将永远有)一个别名,一个简短的、吸引人的别名,你想调用它。这不会有用吗?【参考方案4】:

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

call("myAlias", shell=True)

来自relevant documentation:

如果shellTrue,指定的命令将通过shell执行。如果您主要将 Python 用于增强控制流,它在大多数系统 shell 上提供,并且仍希望访问其他 shell 功能,例如文件名通配符、shell 管道和环境变量扩展,这将非常有用。

别名是一种外壳功能(例如,它们由外壳定义和解释)。

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

如果您不愿意在 python 脚本中使用完整的扩展命令,则必须使用 $ENV environment variable 让 shell 读取其中定义了别名的文件:

call("myAlias", shell=True, env=dict(ENV='/path/to/aliasfile'))

【讨论】:

谢谢!这已经接近一步了,除了现在我收到错误 /bin/sh: myAlias: command not found 。完全按照我的脚本中的方式运行别名,所以这不是采购问题... 默认情况下,别名仅在交互式 shell 中启用。 FWIW,bash 别名不如 bash shell 函数强大。

以上是关于Python subprocess.call 一个 bash 别名的主要内容,如果未能解决你的问题,请参考以下文章

Python subprocess.call 一个 bash 别名

在 Python 中使用 subprocess.call 播放音频

Python下的subprocess.call()使用和注意事项

Python, subprocess, call(), check_call 和 returncode 来查找命令是不是存在

Python subprocess.call 与 cwd 不工作

从Python subprocess.call的输出中的列获取值