
У меня есть следующий скрипт:
#!/usr/bin/env zsh
START_FOREMAN='/usr/bin/zsh -c "source /home/user/.zshrc; foreman start" zsh'
xfce4-terminal --tab -H -T app-server --working-directory=/home/user/git/app -e $START_FOREMAN
xfce4-terminal --tab -H -T api-server --working-directory=/home/user/git/api -e $START_FOREMAN
Обе эти команды зависят от настроек окружения (chruby
конфигурация), поэтому я загружаю свой ./zshrc
файл перед запускомforeman
драгоценный камень.
Однако если я запущу это, а затем попытаюсь Ctrl+C
выйти из долго выполняющегося процесса, оболочка завершится, и я больше не получу приглашение.
Примечание: запуск foreman start в новой оболочке в том же каталоге возвращает мне приглашение после Ctrl+C
.
Редактировать: Похоже, люди зацикливаются на том, что проблема в бригадире, хотя я считаю, что это не так, поскольку это касается, скажем, выполнения ./gradlew bootRun
любого длительного процесса.
Форман определенно уходит:
^CSIGINT received
16:13:09 system | sending SIGTERM to all processes
16:13:10 api.1 | exited with code 130
Как и Spring boot:
java.io.IOException: Stream closed
at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:170)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:291)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at org.gradle.process.internal.streams.ExecOutputHandleRunner.run(ExecOutputHandleRunner.java:51)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
:bootRun FAILED
> Building 100%
В этот момент я ничего не могу сделать — все игнорируется, и мне приходится закрывать вкладку.
решение1
То, что вы наблюдаете, представляет собой комбинацию двух вещей:
Ctrl-C отправляет INT в группу процессов, что означает, что не только ваш долго выполняющийся процесс, но изшпроцесс, в котором он запущен, будет одновременно завершен (и у него не будет возможности перезапуститься).
xfce4-terminal не закроет вкладку после завершения процесса из-за флага -H:
−H, −−hold Заставляет терминал оставаться активным после завершения дочерней команды.
что создает впечатление, что он висит
Самый простой возможный тестовый пример может выглядеть примерно так:
CMD=xeyes
START=$'/usr/bin/zsh -c \''$CMD$'; /usr/bin/zsh\''
xfce4-terminal --tab -H -T mycommand --working-directory=$HOME -e "$START"
Если вы запустите это, «xeyes» будет следовать за вами, пока вы не нажметеCtrl+С, после чего они закроются, а ваш терминал будет выглядеть зависшим.
Но если вместо того, чтобы нажатьCtrl+Свы просто убьете сами xeyes (т.е. с помощью xkill или панели задач оконного менеджера),зшсеанс начнется, как и предполагалось.
Обойти эту проблему можно, перехватив SIGINT и перезапустив оболочку, например так:
CMD=xeyes
START=$'/usr/bin/zsh -c \'trap "exec /usr/bin/zsh" INT;'$CMD$'; exec /usr/bin/zsh\''
xfce4-terminal --tab -H -T mycommand --working-directory=$HOME -e "$START"
Обратите внимание, что вы также можете удалить «-H», чтобы вкладка закрывалась при выходе из оболочки.