【问题标题】:What is the equivalent of 'nohup' in linux PowerShell?linux PowerShell 中“nohup”的等价物是什么?
【发布时间】:2020-11-06 02:03:27
【问题描述】:

我很清楚duplicate question 的存在。但该问题已被标记为已回答,我认为它根本无法回答原始问题。

即使 nohup 的父进程 (shell) 死亡,$ nohup command 也会继续执行命令。更多信息在这里:What's the difference between nohup and ampersand

在 Win32 api 的情况下,我看到 When the system is terminating a process, it does not terminate any child processes that the process has created. Terminating a process does not generate notifications for WH_CBT hook procedures. 行。这是我要问的理想行为。这适用于 win32 powershell 自动。但是对于 linux powershell 的 Start-Job,它只是 powershell 上下文中的后台作业,因为当 powershell 被杀死时它会被杀死。

例子:

➜  ~ powershell-preview -c "Start-Job { /bin/sleep 1000 }"

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
1      Job1            BackgroundJob   Running       True            localhost             /bin/sleep 1000

➜  ~ ps ux  | grep sleep
mvaidya   166986  0.0  0.0   9032   664 pts/11   S+   18:59   0:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox sleep

【问题讨论】:

  • 顺便说一句:即使在 Windows 上,运行使用 Start-Job 创建的作业的子进程也会在启动 shell 退出时被终止。

标签: powershell powershell-core powershell-7.0


【解决方案1】:

使用 Start-Job 或 PowerShell v6+ 的 & background operator 不是一个选项,因为终止作业也会终止从它启动的子进程,这些作业是 - 在 Windows 和类 Unix 平台上 em>。

但是,您可以通过Start-Process cmdlet 实现类似于nohup 的行为:


Unix 类平台上,您可以将 Start-Processnohup 结合使用:
以下示例启动一个后台 PowerShell 实例,即使在您关闭启动终端后该实例仍保持活动状态;它每秒发出一个.nohup 在当前目录中的文件nohup.out 中收集stdout 和stderr 输出,如果它已经存在,则附加到这样的文件:

# Runs for 2 minutes and appends both stdout and stderr output to ./nohup.out
Start-Process nohup 'pwsh -nop -c "1..120 | % { write-host . -nonewline; sleep 1 }"'

警告:从 PowerShell 7.2 开始,通过 SSH 连接运行此命令仅在连接通过ssh 启动时才有效 em>,而不是通过 PowerShell 自己的基于 SSH 的远程处理 cmdlet,例如 Invoke-CommandEnter-PSSession[1]

例如 - 假设用户在目标计算机上的默认 shell 是 pwsh (PowerShell),可以使用以下命令;请注意,选项-t 是必需的,以便分配伪终端(pty),以便nohup 认为其标准输出已连接到终端,因此将其输出发送到文件.\nohup.out) :

ssh -t <user>@<host> 'Start-Process nohup ''pwsh -nop -c \"1..120 | % { write-host . -nonewline; sleep 1 }\"'''

注意\" 的惊人需求,而不仅仅是",这是为了补偿 PowerShell 从 PowerShell 7.1 开始向外部程序传递参数仍然中断的问题 - 请参阅 this answer

相比之下,如果用户在目标计算机上的默认 shell 是 POSIX 兼容 shell,例如 bash,请使用以下命令(从 PowerShell 运行):

# IMPORTANT: If the target machine runs macOS rather than Linux, use the
#            `pwsh`'s *full path*, which is `/usr/local/bin/pwsh` by default.
ssh -t <user>@<host> 'nohup pwsh -nop -c ''1..120 | % { write-host . -nonewline; sleep 1 }'' & whoami >/dev/null'

注意在提交后台作业( &amp;)后使用虚拟命令whoami &gt;/dev/null,这似乎是确保nohup 有足够的时间实际启动其目标命令所必需的。


Windows 上,Start-Process 默认在新的控制台窗口中创建一个独立的进程,您可以使用 -WindowStyle Hidden 在隐藏窗口中启动该进程它将独立于启动外壳保持活动。

# Runs for 2 minutes and appends success output to ./nohup.out
Start-Process -WindowStyle Hidden pwsh '-nop -c "1..120 | % { Add-Content -nonewline nohup.out -Value .; sleep 1 }"'

警告:这不能按原样工作远程处理

  • 在远程会话中,Start-Process 无法以这种方式在单独(隐藏)窗口中启动进程,因此在退出远程会话时,启动的进程也会终止

  • 但是,您可以创建一个断开连接会话,该会话在目标计算机上保持活动状态,直到它被明确删除(或直到目标计算机重新启动);或者,显式创建一个常规(已连接)会话并根据需要保留它 - 但如果调用计算机在任务完成之前重新启动,则任务会再次终止(除非您先显式断开会话)。

一个例子,使用Invoke-Command-InDisconnectedSession开关:

# Launch the command remotely, in a disconnected session, and
# return a session-information object:
$disconnSess = Invoke-Command -Computer <host> -InDisconnectedSession {
  Start-Process -WindowStyle Hidden pwsh '-nop -c "1..120 | % { Add-Content -nonewline nohup.out -Value .; sleep 1 }"'
}

# ... Let the command finish

# Remove the session again
Remove-PSSession $disconnSess

[1] 这些 cmdlet 不分配伪终端 (pty),缺少伪终端会导致 nohup 将其输出打印到 stdout 和 stderr 而不是文件 .\nohup.out。此外,这种意外的直接打印输出可能会导致远程 PowerShell 会话崩溃

【讨论】:

  • @ziyuang,在同一台机器上执行时,该进程应该继续存在。通过 SSH,需要额外的努力,它只能通过 ssh 工作(而不是通过 PowerShell 的远程 cmdlet) - 请参阅我的更新。
猜你喜欢
  • 2016-07-25
  • 2011-07-18
  • 1970-01-01
  • 2018-07-10
  • 1970-01-01
  • 2010-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多