我正在尝试编写一个.sh文件,同时运行许多程序

我试过了

prog1 
prog2

但是它会运行prog1,然后等待prog1结束,然后启动prog2……

那么如何并行运行呢?


当前回答

如果你想用ctrl-c轻松地运行和杀死多个进程,这是我最喜欢的方法:在一个(…)subshell中生成多个后台进程,并捕获SIGINT来执行kill 0,这将杀死subshell组中生成的所有内容:

(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)

你可以有复杂的进程执行结构,所有的事情都可以用一个ctrl-c来结束(只要确保最后一个进程是在前台运行的,也就是说,在prog1.3之后不要包含&):

(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)

如果最后一个命令可能会提前退出,而您希望保持其他所有命令的运行,则添加wait作为最后一个命令。在下面的例子中,sleep 2会先退出,在sleep 4结束之前杀死它;添加wait可以让两者都运行到完成:

(trap 'kill 0' SIGINT; sleep 4 & sleep 2 & wait)

其他回答

如何:

prog1 & prog2 && fg

这将:

prog1开始。 将其发送到后台,但继续打印其输出。 启动prog2,并将其放在前台,因此可以使用ctrl-c关闭它。 当你关闭prog2时,你将返回到prog1的前台,所以你也可以用ctrl-c关闭它。

xargs -P <n>允许并行运行<n个>命令。

虽然-P是一个非标准选项,但是GNU (Linux)和macOS/BSD实现都支持它。

示例如下:

最多同时运行3个命令, 只有在先前启动的进程终止时才启动附加命令。

time xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF

输出如下所示:

1   # output from 1st command 
4   # output from *last* command, which started as soon as the count dropped below 3
2   # output from 2nd command
3   # output from 3rd command

real    0m3.012s
user    0m0.011s
sys 0m0.008s

计时显示这些命令是并行运行的(最后一个命令仅在最初3个命令中的第一个命令终止后启动,但执行得非常快)。

xargs命令本身在所有命令完成之前不会返回,但是您可以在后台执行它,使用控制操作符&终止它,然后使用内置的wait等待整个xargs命令完成。

{
  xargs -P 3 -I {} sh -c 'eval "$1"' - {} <<'EOF'
sleep 1; echo 1
sleep 2; echo 2
sleep 3; echo 3
echo 4
EOF
} &

# Script execution continues here while `xargs` is running 
# in the background.
echo "Waiting for commands to finish..."

# Wait for `xargs` to finish, via special variable $!, which contains
# the PID of the most recently started background process.
wait $!

注意:

BSD/macOS xargs要求您显式地指定并行运行的命令的数量,而GNU xargs允许您指定-P 0以并行运行尽可能多的命令。 并行运行的进程的输出在生成时到达,因此它将不可预测地交错。 正如Ole的回答中所提到的(大多数平台都不是标准的),GNU并行在每个进程的基础上方便地序列化(分组)输出,并提供了许多更高级的特性。

有一个非常有用的程序调用nohup。

     nohup - run a command immune to hangups, with output to a non-tty

使用GNU Parallel http://www.gnu.org/software/parallel/,它就像:

(echo prog1; echo prog2) | parallel

或者如果你喜欢:

parallel ::: prog1 prog2

了解更多:

观看介绍视频快速介绍: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 浏览教程(man parallel_tutorial)。您的命令行 会因此爱你的。 阅读:Ole Tange, GNU Parallel 2018 (Ole Tange, 2018)。

如果你是:

在Mac上使用iTerm 想要启动各种长期打开的进程,直到按Ctrl+C 希望能够轻松地看到每个进程的输出 希望能够轻松地使用Ctrl+C停止特定进程

如果你的用例更多的是应用监控/管理,一种选择是编写终端本身的脚本。

例如,我最近做了以下事情。当然,它是特定于Mac的,特定于iTerm的,并且依赖于已弃用的Apple Script API (iTerm有一个更新的Python选项)。它没有赢得任何优雅奖,但完成了任务。

#!/bin/sh
root_path="~/root-path"
auth_api_script="$root_path/auth-path/auth-script.sh"
admin_api_proj="$root_path/admin-path/admin.csproj"
agent_proj="$root_path/agent-path/agent.csproj"
dashboard_path="$root_path/dashboard-web"

osascript <<THEEND
tell application "iTerm"
  set newWindow to (create window with default profile)

  tell current session of newWindow
    set name to "Auth API"
    write text "pushd $root_path && $auth_api_script"
  end tell

  tell newWindow
    set newTab to (create tab with default profile)
    tell current session of newTab
        set name to "Admin API"
        write text "dotnet run --debug -p $admin_api_proj"
    end tell
  end tell

  tell newWindow
    set newTab to (create tab with default profile)
    tell current session of newTab
        set name to "Agent"
        write text "dotnet run --debug -p $agent_proj"
    end tell
  end tell

  tell newWindow
    set newTab to (create tab with default profile)
    tell current session of newTab
        set name to "Dashboard"
        write text "pushd $dashboard_path; ng serve -o"
    end tell
  end tell

end tell
THEEND