我尝试从 bash 文件在 2 个不同的 TMUX 窗格中运行 2 个脚本。问题是它们都是阻塞的,所以一旦我从一个窗格执行一个进程,我就无法移动到另一个窗格来执行另一个作业。
我怎样才能克服这个问题?
我将发布代码示例。
#! /bin/bash
tmux split-window -v
tmux select-pane -t 0
./blocking_script_1
tmux select-pane -t 1 #doesnt happen
./blocking-script_2 #doesnt happen
Run Code Online (Sandbox Code Playgroud)
谢谢
利亚姆
\n\n\n我正在尝试从 bash 文件在 2 个不同的 TMUX 窗格中运行 2 个脚本。问题是它们都是阻塞的,所以一旦我从一个窗格执行一个进程,我就无法移动到另一个窗格来执行其他作业。
\n
你似乎认为在这行之后
\n\ntmux select-pane -t 1\n
Run Code Online (Sandbox Code Playgroud)\n\n下一行将在选定的窗格中执行。这不是真的。即使您的主脚本在后台运行这两个脚本,它们仍然会在主脚本运行的地方运行。
\n\n另一个答案建议send-keys
将命令注入其他窗格。这很麻烦而且不太可靠(例如,您需要确保那里有一个空闲的 shell,并且命令行为空)。
在新创建的窗格中运行脚本。例子:
\n\n# create a new window and run the first script\ntmux new-window -n my-scripts -c "$PWD" ./blocking_script_1\n# split the newly created window and run the second script in a new pane\ntmux split-window -v -c "$PWD" -t :my-scripts ./blocking-script_2\n
Run Code Online (Sandbox Code Playgroud)\n\n或者,如果您在一个窗格中运行主脚本,则在另一个窗格中启动另一个目标脚本后,您可以将其中一个目标脚本作为主脚本的一部分正常运行:
\n\n# split the current window and run the second script in a new pane\ntmux split-window -v -c "$PWD" ./blocking-script_2\n# run the first script normally\n./blocking_script_1\n
Run Code Online (Sandbox Code Playgroud)\n\n如果您想利用现有的窗格,那么您需要respawn-pane
,可能需要-k
杀死当前在目标窗格中运行的任何内容(在这种情况下,不要以主脚本运行的窗格为目标,除非它是主脚本中的最后一个东西)脚本必须做)。
您可能会发现和-d
选项很有用。它使新创建的窗口/窗格不会成为当前窗口/窗格。从现在开始,在这个答案中,如果我需要使任何新窗格成为当前窗格,我将仅最后或一次创建所有窗格。这是为了避免当您将任何代码片段粘贴到 tmux 中的交互式 shell 中时发生意外,并且 tmux 在整个代码片段到达 shell 之前选择另一个窗格。new-window
split-window
-d
select-window
select-pane
请注意,上述任何运行的命令实际上都在窗格中./blocking-script_2
运行 POSIX shell ( )。sh
shell 解释命令 ( ./blocking-script_2
)。脚本退出后,shell 也退出。的一些实现sh
可能足够聪明,可以首先检测exec
到它们的能力。./blocking-script_2
脚本退出后,窗格中没有进程,因此通常窗格会被破坏。
./blocking-script_2
退出后有几个选项可以查看输出:
而不是单独./blocking-script_2
运行脚本和任何不会自行退出并且不会按顺序生成(太多)输出的命令;额外的命令将使窗格保持活动状态;例子:
# it can be an interactive shell\ntmux \xe2\x80\xa6 \'./blocking-script_2; exec bash -i\'\n# or simply a loop like this\ntmux \xe2\x80\xa6 \'./blocking-script_2; while sleep 3600; do :; done\'\n
Run Code Online (Sandbox Code Playgroud)使用remain-on-exit
窗口选项;理论上这似乎是最优雅的。
remain-on-exit on
请注意,此片段有缺陷:
\n\n# flawed\ntmux new-window -dn my-scripts -c "$PWD" ./blocking_script_1\ntmux set-window-option -t :my-scripts remain-on-exit on\ntmux split-window -dvc "$PWD" -t :my-scripts ./blocking-script_2\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n如果./blocking_script_1
退出得足够快,窗口可能会在其他命令运行之前被销毁;那么他们将找不到窗口并失败。比较竞争条件。几个想法:
用于set remain-on-exit
设置会话选项,或set-window-option -g remain-on-exit
设置全局窗口选项。例子:
# flawed\ntmux set-window-option -g remain-on-exit on\ntmux new-window -dn my-scripts -c "$PWD" ./blocking_script_1\ntmux split-window -dvc "$PWD" -t :my-scripts ./blocking-script_2\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n然后:
\n\ntmux set-window-option -gu remain-on-exit\n
Run Code Online (Sandbox Code Playgroud)\n\n所有没有显式设置该选项的窗口都将使用会话选项或全局窗口选项。这种继承有些复杂,我在这里不再解释(请参阅参考资料man 1 tmux
)。当窗格消失时会选中该选项,因此在两个脚本退出之前您无法将其更改回来。这种方法可能会在一段时间内影响许多窗口。如果其他某个窗格进程退出,该窗格将不会被破坏,而通常情况下它会被破坏。
用于设置在创建新窗口时set set-remain-on-exit
设置的会话选项:remain-on-exit
# flawed\ntmux set set-remain-on-exit on\ntmux new-window -dn my-scripts -c "$PWD" ./blocking_script_1\ntmux set -u set-remain-on-exit\ntmux split-window -dvc "$PWD" -t :my-scripts ./blocking-script_2\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n这根本不会影响现有的窗口。不过,如果创建了另一个窗口(由另一个脚本或您手动创建)并且时机恰到好处,set-remain-on-exit
也会对其进行设置remain-on-exit
。
创建一个带有虚拟原始窗格的窗口,该窗格不会自行退出;设置窗口;生成至少一个应该存活的窗格;销毁虚拟窗格:
\n\n# flawed (because of a bug)\ntmux new-window -dn my-scripts \'while sleep 100; do :; done\'\ntmux set-window-option -t :my-scripts remain-on-exit on\ntmux split-window -dvc "$PWD" -t :my-scripts ./blocking-script_1\nsleep 2\ntmux kill-pane -t :my-scripts.0\ntmux split-window -dvc "$PWD" -t :my-scripts ./blocking-script_2\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n我发现如果kill-pane
在创建虚拟窗格后过早创建它,那么我的 tmux 服务器将会崩溃。这不应该发生,它看起来像一个错误。不优雅的人sleep 2
可能会在实践中发挥作用;但从理论上讲,在某些情况下任何延迟可能都不够长。
exec
让新窗口中的每个窗格在调用目标脚本之前设置正确的选项:
# not flawed (AFAIK), cumbersome\ntmux new-window -dn my-scripts -c "$PWD" \'tmux set-window-option -t :my-scripts remain-on-exit on; exec ./blocking_script_1\'\ntmux split-window -dvc "$PWD" -t :my-scripts \'tmux set-window-option -t :my-scripts remain-on-exit on; exec ./blocking-script_2\'\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n“每个窗格”是因为理论上第二个窗格可能会在第一个 shell 运行之前死亡tmux set-window-option \xe2\x80\xa6
。如果发生这种情况并且只有第一个 shell 尝试更改选项,则保存第二个脚本的窗格将被销毁。
您想要运行的脚本越多,这种方法就变得越麻烦。
正如您所看到的,原始的有缺陷的代码片段可能受到竞争条件的影响。当我们尝试修复它时,会出现新的竞争条件。以这种方式使用 tmux 时,这种情况很常见。tmux new-window \xe2\x80\xa6
是tmux服务器的命令,tmux
这里只是一个客户端。客户端成功退出后,可以确定已经创建了一个新窗口;但你无法真正知道其中发生了什么,在什么阶段,或者窗口是否还没有被破坏。
在您的特定情况下,在 tmux 内的 shell 中运行主脚本并定位其窗口可以保证窗口存在。脚本做的第一件事应该是设置remain-on-exit on
。
在 tmux 中处理竞争条件的正确通用方法仍然是wait-for
:
\n\n\n\n\n
wait-for [-L | -S | -U] channel
\n(别名wait
:)当不带选项使用时,阻止客户端退出,直到使用
\nwait-for -S
相同的channel
. [\xe2\x80\xa6]
我的测试表明tmux wait -S foo
永远不会等待。当它被调用时,所有等待的都tmux wait foo
被唤醒,它们退出。但如果没有tmux wait foo
等待,那么“唤醒力量”就会被推迟,下一个(未来)tmux wait foo
将不会等待。这意味着这两个命令可以按任何顺序调用。如果tmux wait foo
退出,那么您可以确定tmux wait -S foo
已经发生过(刚刚发生过或过去发生过)。
修复了原始片段:
\n\n# robust (AFAIK)\ntmux new-window -dn my-scripts -c "$PWD" \'tmux wait baz; exec ./blocking_script_1\'\ntmux set-window-option -t :my-scripts remain-on-exit on\ntmux wait -S baz\ntmux split-window -dvc "$PWD" -t :my-scripts ./blocking-script_2\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n第一个窗格中的 shell 将被阻止,tmux wait
直到主脚本配置该选项之后。那么第一个脚本多久退出并不重要。
两个 shell 都等待一切准备就绪的方法在美学上对我来说是令人愉悦的:
\n\n# flawed though\ntmux new-window -dn my-scripts -c "$PWD" \'tmux wait baz; exec ./blocking_script_1\'\ntmux split-window -dvc "$PWD" -t :my-scripts \'tmux wait baz; exec ./blocking-script_2\'\ntmux set-window-option -t :my-scripts remain-on-exit on\ntmux wait -S baz\ntmux select-window -t :my-scripts\n
Run Code Online (Sandbox Code Playgroud)\n\n然后我意识到虽然我可以wait
以任何顺序运行,但对于 2x和wait -S
来说却不是这样:wait
wait -S
wait
, wait
,wait -S
将解锁两个 shell;这可以推广到更多wait
s。确切地说,一个人wait foo
可以击败竞争条件。wait foo
一次不止一个会产生另一种竞争条件。
归档时间: |
|
查看次数: |
2050 次 |
最近记录: |