在使用VSCode远程开发时,经常碰到有一些脚本要跑很长时间的情景,比如提交并跟踪MapReduce任务、训练模型、处理数据、网络IO等。这时候我们希望脚本自己在后台跑,但一个很头疼的问题是脚本跟终端挂在一起。一旦去吃饭电脑进入休眠模式,本地的VSCode很可能会断开和远程开发机的连接,进而导致终端自动退出。而之前说脚本是跑到终端上的,这就导致吃完饭回来发现脚本被终止的尴尬情况。

为了让脚本流畅的跑到后台,在这里盘点几种Linux系统下终端关闭后继续执行命令的方法。

1. 使用 nohup

nohup (no hang up) 命令可以让你在关闭终端后继续执行命令,并将输出重定向到一个文件:

1
nohup your_command & disown

优点: - 简单易用,只需在命令前加上 nohup 并在后面加上 &。 - 命令会继续运行,即使你退出终端。

缺点: - 输出会默认写入 nohup.out 文件,可能需要手动处理日志文件。如果你想输入到别的文件,使用">"指令重定向输出。 - 没有提供重新连接的功能,如果你想查看命令的执行情况,需要查看输出文件。 - 如果没有disown命令,实测终端意外关闭是会影响后台命令的执行的。之前是nohup之后就把运行的那个终端手动exit退出掉。但这两种办法都有个问题,不管disown还是exit了,新的shell都不能控制原来的脚本了。如果跑一半出问题了,只能ps -aux | grep xxx去找之前的进程id,然后kill掉。如果原来的shell里要配置环境变量,这里还得重新配置一波,很折磨。

2. 使用 screen(推荐)

screen 是一个窗口管理器,可以让你在多个虚拟终端之间切换,并在断开连接后继续运行命令:

1
2
3
screen -S session_name
your_command
# 按下 Ctrl+A 然后按 D 来分离会话

你可以使用 screen -r session_name 来重新连接到该会话。

优点: - 可以在会话之间切换,支持多窗口。 - 断开连接后命令继续运行,可以随时重新连接查看命令的执行情况,screen -r session_name非常好用。 - 支持多用户会话共享。

缺点: - 配置和使用相对复杂,需要学习一些基本命令。 - 默认情况下,窗口管理和导航操作需要记住一些快捷键。比如要知道按下 Ctrl+A 然后按 D 来分离会话,不然会僵住。

更高级的还可以使用 tmux,它与screen类似,但功能更强大。由于我们这边只讨论终端关闭后执行命令,screen完全够用,出于简单使用screen就够了。

3. 使用 &disown

你可以将命令放到后台执行,并使用 disown 命令将其从当前 shell 会话中分离:

1
2
your_command &
disown

这个方法感觉和nohup一样,不过似乎没有默认把输出定向到nohup.out,会丢日志。

4. 使用 at 命令

at 命令可以在指定的时间执行命令,即使你已经退出了终端:

1
echo "your_command" | at now

优点: - 可以定时执行命令,适用于需要延迟执行的任务。 - 即使终端关闭,命令也会按计划执行。

缺点: - 主要用于一次性任务,不适合长时间运行的后台进程。 - 没有提供重新连接的功能,无法查看命令的实时执行情况。

好处就是可以执行定时任务,at能够支持多种时间,感觉还是比较灵活的,比如:

1
2
3
4
5
6
7
8
9
10
# 指定具体时间
at 15:00

# 指定日期和时间
at 14:30 2024-07-26
at 2024-07-26 15:00

# 指定相对时间
at now + 1 hour
at 10:00 tomorrow

总结

  • 简单的后台运行:如果你不需要重新连接查看输出,nohup& + disown 是不错的选择。
  • 会话管理和多窗口:如果你需要在多个会话之间切换,并能随时查看和管理命令的执行情况,screentmux 更加适合。tmux 功能更强大,但 screen 更简单易用。
  • 定时任务:如果你需要定时执行任务,at 是一个不错的选择。这里需要用一点管道知识,通过echo命令将你要执行的命令传递给at,使用方法是echo "your_command" | at nowat支持多种时间指定方式。

根据实际需求选择合适的方法,可以提高效率并更好地管理后台任务(可以安心干饭了)。