linux PowerShell 中 'nohup' 的等价物是什么?

What is the equivalent of 'nohup' in linux PowerShell?

我很清楚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

使用 Start-Job or PowerShell v6+'s & background operator 不是一个选项,因为终止作业也会终止从它启动的子进程,这些作业是 - Windows 和 Unix-like 平台.

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


Unix-like 平台 上,您可以将 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 启动的,而不是通过 PowerShell 自己的 SSH-based 远程处理 cmdlet,例如 Invoke-Command and Enter-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 开始对外部程序的 still-broken argument-passing 7.1 - 见 .

相比之下,如果用户在目标计算机上的默认 shell 是 POSIX-compatible 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'

注意在提交后台作业 ( &) 后使用虚拟命令 whoami >/dev/null,这似乎是确保 nohup 有足够的时间来实际上启动它的目标命令。


On Windows,其中Start-Process默认在新控制台创建独立进程window,您可以使用 -WindowStyle Hidden 在隐藏的 window 中启动该进程,该进程将独立于启动 shell.

保持活动状态
# 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 }"'

警告:这个不起作用as-is工作远程处理:

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

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

一个例子,使用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 会话 崩溃