Ble.sh: nohup(1)コマンドの挙動について

Created on 7 Sep 2018  ·  11Comments  ·  Source: akinomyoga/ble.sh

nohup(1)コマンドをバックグラウンドジョブとして実行したのちにシェルをログアウトしようとすると,ジョブが残っているという旨の警告が出てログアウトできない。
Commit ID: 87ba74b
Version of GNU Bash: 4.4.12

症状

$ nohup xlogo > /dev/null &
$ @

ここでCtrl+dなどとしてログアウトしようとしても,ジョブが残っているという警告が表示され,ログアウトできません。
ちなみにbleshを読み込まずに起動するとこの現象は発生しません。
また,checkjobsが原因かと思い,有効・無効を試しましたが,変化はないようです。

bug

All 11 comments

すみません。そういう仕様にしていました (本当にログアウトしたい時には exit と打てば良いので)。後で変更することにします

本当にログアウトしたい時には exit と打てば良い

細かいことを訊きます。この場合,exit(1)を実行してもログアウトできないんですが,そういう仕様ということですか?

あれ、確かにログアウトできませんね…。ログアウトできる仕様のつもりでした。調べてみます

すみません。仕事の合間にやってるので余り時間が取れていないですが報告だけ簡単にしておきます

C-d での終了に関し

期待する動作について確認させていただきたく思います。

  • Q. nohup していないジョブが残っている場合にも C-d で即終了するのが望ましいか、それともその場合にはやはり終了せずに警告を出す方が望ましいか。

またこれを期に兼ねてから放置していた IGNOREEOF も対応しようかと思います。checkjobs にもできる範囲で対応してみますね。

また恐らく bleopt で動作を切り替えられるようにして、(これは趣味なのですが) 既定の動作は現在の動作にして、マニュアル (これは enhance-complete の後に書く予定) に記述しようと考えております。もしこの既定の動作について問題が発生する可能性などありましたらご意見をお聞かせください。

exit で終了できないことに関し

すみませんが、そちらの状況をもう少し詳しく教えていただければ幸いです。こちらの手元では以下のような状況で少し異なるようです:

  • ジョブがバックグラウンドで走っている時 (nohup command & としたかどうかに拘わらず):

    • その Bash がセッションリーダーの時: exit すると多少の遅延 (1--2秒) の後に終了する

    • セッションリーダーでない時: 遅延時間なくすぐに終了する

  • Suspend 状態のジョブがある時 (Suspend しているのが nohup されたものかどうかに拘わらず):

    • 1回目の exit で終了しない (Bash の動作と同じ)。2回目以降の exit でも終了できない (Bash の動作と異なる)。

前者について。こちらでは、遅延はあるもののログアウトはできるようです。遅延の原因は今の所不明です。

後者について (nohup したジョブを suspend で放置するのが普通かどうかはともかくとして)。ble.sh 自体は exit に干渉していないので Bash の元々の動作と同じになるということを期待していたのですが、ble.sh を使っていると exit を本当の意味で「連続」で2回実行することができないので、通常の exit と同様のことができないのでした。2回連続で exit が呼び出されることをもし検出できれば、その時に ble.sh 側で exit &>/dev/null; exit を内部的に実行するようにすれば終了できます。と思ったのですが、「2回連続で呼び出された」ということの検出方法が今の所思い浮かびません。

Ans: Ctrl+dの挙動の要望

できるだけ,Bashのそれに合わせてほしいです。
つまり:
nohup(1)されていないジョブが残っている場合で
a. checkjobsが無効
exit(1)で即終了
b. checkjobsが有効
exit(1)を一度実行すると警告,二度目で終了

exit(1)の挙動についてはすこし待ってください。ざっと調べたところ,おっしゃる遅延は見受けられず,またcheckjobsの有効いかんによって変化するようでした。精査したいところです。

Re: Ans: Ctrl+dの挙動の要望

9f0f7dd 対応するのに enhance-complete ブランチの方で実装した機能が必要だったので、取り敢えず enhance-complete ブランチの方に実装しました。申し訳ありませんが、enhance-complete がマージされるまでは disown などして対処していただけると幸いです (もしくは enhance-complete ブランチの方をお使いいただければ幸いです)。

有効にするには bleopt allow_exit_with_jobs=1 を設定していただくことにしました (既定はジョブが残っている内は終了しないまま)。この時、ジョブが残っていても C-d で終了するようになります。但し、停止中のジョブがある場合、または、shopt -s checkjobs かつ実行中のジョブがある場合には、即終了せず2回連続する同じ widget の呼び出しによって終了します。

Re: exit で終了できないことに関し

なるほど、確かに shopt -s checkjobs だと exit では終了できなくなりそうです。対策方法 (検出方法) を考えてみることにします (検出方法ないかもしれません…)。

今の所思いつく案: exit 組み込みコマンドを関数で上書きして、呼び出しを記録するようにする。連続するコマンド実行で exit が実行された時に ble.sh の側で終了する。この方法の問題点は以下の通りです。

  • 停止中ジョブがある時、exit; exit としても Bash と違い終了できない。 あ、これ自体は検出できます。ただ exit; do-something; exit と区別が付きません…
  • 停止中ジョブがある時、do-something; exit を2回実行すると Bash と違い終了してしまう。

「Bash と同様と見せかけて微妙に異なる不自然な動作をする」というのは質が悪いのでこの方法は採用し難いです。

IGNOREEOF

0e62c5f IGNOREEOF に関しても enhance-complete ブランチの上ですが対応しました。

Re: exit で終了できないことに関し

相変わらず良い方法は思い浮かびませんが「N秒以内に再度 exit を呼び出したら終了」という仕様にする手もあるかもしれませんね。

なるほど。

$ exit; comecmd; exit
# ---
$ somecmd; exit

↑こういったコマンドラインは,使ったことがなく,思い付きませんでした。こういった場合でも内部でバックグラウンドジョブやcheckjobsの検査をしなくてはならないので,Bashの上に実装されているbleshでは対処が難しいということですよね。

ところでCtrl+dが押しやすく,いわゆる〝誤爆〟しやすいのに対して,$ exitというコマンドラインはそういったことがあまり起きませんよね。Bashが行っているジョブを検査→終了させないという挙動は,(根拠不詳ですが)そのような失敗を防ぐためにあると思われます。いっそのこと,exit(1)ではジョブのあるなしに関わらず終了するといったような設定でもいいのかもしれません。

Re: exit で終了できないことに関し

↑こういったコマンドラインは,使ったことがなく,

まあ、実際に exit; somecmd; exitsomecmd; exit を直に入力することがあるかは謎ですが、例えばユーザが my-super-exit() { echo "I'm exiting."; exit; } とやって my-super-exit を実行したとか、めぐりめぐってそういう部分構造が発生するという可能性は常に排除できないので、余り中途半端なことはしたくないのでした。

いっそのこと,exit(1)ではジョブのあるなしに関わらず終了するといったような設定でもいいのかもしれません。

ありがとうございます! その方向で考えてみたら良いアイディアが思い浮かびました。その場でユーザに明示的に確認して終了すれば良いです。そもそも「2回連続でexit を実行したら」という分かりにくい仕様を Bash が取っているのが謎に思われてきました。

というわけでその様に実装してみました a136f79 (enhance-complete)。以下のような形に動作します。

$ sleep 100
    # ← ここで C-z を入力
[1]+  停止                  sleep 100
[ble: exit 148]
$ exit    # ← 入力
[1]+  停止                  sleep 100
[ble: There are stopped jobs] Leave the shell anyway? [yes/No] asdf    # ← 入力
[1]+  停止                  sleep 100
[ble: There are stopped jobs] Leave the shell anyway? [yes/No] yes    # ← 入力
[ble: exit]

Bashが行っているジョブを検査→終了させないという挙動は,(根拠不詳ですが)そのような失敗を防ぐためにあると思われます。

実際それで間違いないでしょう。議論させていただきまして気づいたのですが、だいぶ人によってシェルのジョブの扱い方は違うものですね。私の場合は、正直すぐ誤爆します。C-d も誤爆するし exit も誤爆します。その為に PS1\j (ジョブ数) も入れているのですが、それでも誤爆してしまうのです (たぶん screen で大量のバッファウィンドウを抱えて適当に操作しているからなのですが。Bash (ble.sh) が止めてくれると信じているから注意が向いていないという側面もあります)。

更に、冷静になってみれば、ジョブの何たるかを知らずに使っている人も世の中にはたくさんいることにも注意しなければなりませんね。ジョブが残っている場合に C-d で終了しない、という ble.sh の既定の動作もそういう人には混乱を与えるでしょうから、表示するメッセージを少し変更しました afb73cb。例:

$    # ← C-d
[ble: There are remaining jobs. Use "exit" to leave the shell.]
[1]+  実行中               sleep 100 &

取り敢えずこの Issue は閉じますね。申し訳ありませんが、enhance-complete をマージするまでは、シェルを抜ける前に一つ一つ disown を実行していただくことになります。よろしくお願いいたします。

@cmplstofB ところで、先の議論 #2 (Support vi-mode) の最後で「新しく個別の Issue として問題点を報告していただいて良い」という様に書いてしまいましたが、問題点以外にも提案や要望など何でも気軽に Issue として報告して頂ければ幸いです。

Was this page helpful?
0 / 5 - 0 ratings