【问题标题】:Run shutdown command in background after delay on windows在 Windows 上延迟后在后台运行关机命令
【发布时间】:2016-12-17 19:21:52
【问题描述】:

我正在尝试在运行 python 客户端程序的 Windows 机器上运行命令。它需要在执行命令之前向服务器返回一个值。

def shutdown():
    if OS_LINUX:
        os.system("sleep 10s && sudo shutdown &")
    elif OS_WIN:
        os.system(<What to put HERE>)
    return (1,"Shutting down")

如您所见,unix 命令运行良好。

在后台,它会运行 sleep 10 秒,然后运行 ​​sudo shutdown。该函数被允许正确返回,并且在运行“sudo shutdown”之前,服务器会收到客户端正在关闭的通知。

但是,在 Windows 方面,我似乎无法在延迟后运行 shutdown -s 并在后台运行它。

这是我目前所拥有的:

start /b /wait timeout 10 && shutdown -s

我尝试了它的许多变体:带/不带 /wait 和 /b,使用 ping 代替超时,将 ping/timeout 的输出发送到“nul”等。

这个是最接近我想要的,但是 timeout 接管命令行直到它完成,这不允许我的 return 语句在运行“shutdown -s”之前在 shutdown() 中被覆盖。这会使服务器一直挂起,直到超时,这不是我希望用户看到的,尤其是因为我不能保证客户端没有在服务器告诉它关闭的同时失去连接。

我可以通过在批处理脚本中抛出“timeout 10 && shutdown -s”并使用 os.system("start /b shutdown_script.bat") 在后台运行它来解决问题,但是这个客户端程序出于分发原因,需要只是一个可移植文件。

unix 上的解决方案很简单,我在 dos 上缺少什么?

编辑:运行 os.system("shutdown -s") 命令(至少在 win10 上)会导致一个屏幕显示给用户,说系统将被关闭。这允许我的函数正常工作并向服务器返回一个值。对于像休眠(“shutdown -h”)这样的其他命令,情况并非如此,在旧版本的 Windows 上也不一定如此。其他命令仍然存在问题,例如远程关闭客户端程序。

EDIT2:我还需要运行休眠和注销命令。分别关闭 -h 和 -l。 shutdown 的 -t 参数仅适用于 -s 和 -r (至少在 windows 10 上)

【问题讨论】:

  • /l(注销)和/p(关机)调用ExitWindowsEx,不支持超时。 /h(休眠),如果支持和启用,通过NtInitiatePowerAction 系统调用实现,不支持超时。 /s(关机)和/r(重启)调用InitiateSystemShutdownEx,除了/s/hybrid配对调用InitiateShutdown。两者都支持最长 10 年的超时。
  • 您可以使用 Python 内部的通用解决方案,例如 threading.Timer,它通过 subprocess.check_call 执行关机命令。如果您正在运行 /s/r,它们支持超时并向用户发出系统范围的警告,那么您可以跳过计时器。

标签: python windows command-line


【解决方案1】:

这个命令对我来说很好用:

shutdown /t 10 /s

【讨论】:

  • /t 选项不适用于 /l、/h 或 /p 选项。由于某些奇怪的原因,它不适用于 /s 以外的任何东西。
  • “不可用”是什么意思。帮助中没有列出?命令拒绝吗?什么版本的窗口?
  • 我正在运行 Win10。使用 /h 或 /l 运行 shutdown /t 不会运行。相反,它列出了关机命令的正确用法(就像您运行“帮助关机”一样)。 I can only find one source that says anything about running /t with /h or /l.
【解决方案2】:

所以我将把你带到命令窗口来显示超时,并且一旦定时器到了你希望SHUTDOWN 命令执行并退出。这是我会做的:

echo off
goto :a
cls

:a
cls
timeout 10 
cls

:b
cls
shutdown -s >nul 
cls

如果您想要更短的版本,也可以使用此命令:

shutdown /t 10 /s

【讨论】:

    【解决方案3】:

    我最终使用 schtasks 解决了这个问题,因为 shutdown 只支持 /s 和 /r 的超时。

    python 代码为当前时间添加 1 分钟的偏移量(schtasks 不以秒为单位),然后使用 /f 参数调用 os.system("schtasks.....") 以避免 schtasks 阻塞控制台要求 y/n 覆盖。

    def get_time_offset(offset):
        now = datetime.datetime.now()
        offset_now = now + datetime.timedelta(minutes=offset)
        offset_now_time = offset_now.time()
        future_time = (str(offset_now_time.hour) + ":" + str(offset_now_time.minute) + ":" + str(offset_now_time.second) )
    return future_time
    
    def sch_task(name, time, task):
        os.system("schtasks /create /tn \"" + str(name) + "\" /sc once /st " + str(time) + " /tr \"" + str(task) + "\" /f")
    

    最终调用如下所示:

    sch_task("client_hibernate", get_time_offset(1), "shutdown /h")
    

    它会在通话后 1 分钟运行。

    此解决方案的唯一问题是 schtasks 仅具有按分钟计算的精度,因此您不能将任务安排在未来不到一分钟的时间。

    我可能会在 python 中编写一个多线程计时器来运行命令,而不是依赖于 windows 的 schtasks 和 linux 的 sleep。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-22
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      • 2015-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多