繁体   English   中英

从命令行调用 bash 脚本和通过 python 执行它的区别

[英]Difference between calling a bash script from the commandline and executing it via python

我目前正在通过 Django 自动化一些流程。 为此,我有一个 shell 脚本,它为我执行某些任务。 我的网络界面有一个“开始进程”按钮和一个“停止进程”按钮。

我想出了使用 shell 脚本的进程 ID 来终止进程的想法,当我想中止它时。 我的start.sh看起来像这样:

pid=$$; 
source ./stop.sh || true
echo $pid > "./processid.txt"; 
#do the actual stuff

我的stop.sh看起来像这样:

pid=$(head -n 1 ./processid.txt)
kill $pid

它的作用是获取进程 ID 并将其临时存储在变量中,然后停止脚本(如果在脚本运行之前),然后将进程 ID 保存到processid.txt文件中。 我的 stop.sh 只是将此 id 从文件中取出并终止该进程。

这确实可以从命令行工作......但是当我从我的 python 代码执行它时它不会。 我这样称呼它:

def start_bot():
    popencommand = "sh -c \"cd ~/thetargetfolder && ./start.sh\"" 

    Popen(popencommand, shell=True)

def stop_bot():
    popencommand = "sh -c \"cd ~/thetargetfolder && ./stop.sh\""

    Popen(popencommand, shell=True)

出于某种原因,这似乎不起作用。 我怀疑这与调用 python 脚本时我在start.sh中获得的进程 ID 不是正确的有关...

当您使用subprocess.Popen("sh -c 'cd /somewhere &&./whatever'", shell=True)时,您是在告诉 Python 启动运行三个进程的一系列事件:

  • 首先,因为shell=True使 Python 运行sh -c '...yourcode...' ,它启动了shell=True请求的第一个sh副本
  • sh的第一个副本运行代码sh -c 'cd /somewhere &&./whatever' ,因为这是您给 Python 的字符串,因此它会启动sh第二个副本。
  • sh的第二个副本运行cd /somewhere &&./whatever 如果./whatever是 shell 脚本,则意味着它启动了第三个shell。

这是很多不必要的复杂性! 没有理由拥有多个shell - 运行./whatever的那个,由操作系统根据其 shebang( #!/bin/sh#!/usr/bin/env bash等调用)。


您可以通过下降到只有一个shell(运行您的脚本的运行)来消除其中的一些问题。 确保脚本具有有效的 shebang( #!/usr/bin/env bash或类似的)并且是可执行的( chmod +x start stop )。

def start_bot():
    subprocess.call(
      [os.path.join(os.path.expanduser('~/thetargetfolder'), './start')],
      cwd=os.path.expanduser('~/thetargetfolder')
    )

def stop_bot():
    subprocess.call(
      [os.path.join(os.path.expanduser('~/thetargetfolder'), './stop')],
      cwd=os.path.expanduser('~/thetargetfolder')
    )

Finally, you can do even better by not using a shell for this at all, but just writing your logic directly in Python, or (even better than that;) relying on your operating system's process supervisor (most modern Linux distros ship systemd for the目的。而 MacOS 附带 launchd)。 如果您定义yourprogram.service ,则systemctl start yourprogram启动脚本运行,而systemctl stop yourprogram将其杀死——您可以将其配置为在启动时自动启动,或在计时器上,或在任何程序连接到预先打开的套接字时自动启动,或者你喜欢的其他方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM