コマンド実行後にBashを実行し続ける方法は?


29

私はこのような何かを実行したいと思います:

bash -c "some_program with its arguments"

しかし、対話型bashをsome_program終了後も実行し続けるには。

私はseys -cとして良い方法ではないと確信していman bashます:

対話型シェルは、非オプション引数なしで、および-cオプションなしで開始されたシェルです

だからこれを行う方法は?

主な目標はここに記載されています

注意

  • some_programは時々終了する必要があります
  • 背景に置きたくない
  • bashは他の何かをするために当時のままにしたい
  • プログラムを再度実行できるようにしたい

1
目標がその複雑なものである場合は、ここでも説明する必要があります。それはちょうどアドバイスだ
Kiwy

1
ここではできるだけ短く、非常に正確に説明しようとしました。しかし、私はほとんどの人が詳細に集中せず、他の何かを提案しようとは思わなかった。明確にするためにいくつかメモを付けます。
pawel7318 14

その他の質問での端末エスケープは何ですか?説明する目標は実行可能ですが、I / Oを処理する必要があります。通常のサブシェルは、通常のファイルを介してターミナルエスケープされたI / Oを簡単に処理できません。あなたはになりますpty.
mikeserv

ちなみに、以下の私の答えでそれが機能する唯一の理由は、私が端末を盗むからです。しかし、最終的には、親プロセスがそれを取り戻す可能性があります-そして、4kbのバッファーを見ています。
mikeserv 14

プログラムをバックグラウンドにしたくないのはなぜですか?前景に置いて、いくつかのbashを行い、バックグラウンドで起動しますfg
ベルンハルト

回答:


8
( exec sh -i 3<<SCRIPT 4<&0 <&3                                        
    echo "do this thing"
    echo "do that thing"
  exec  3>&- <&4
  SCRIPT
)

exec $0.または、これらのファイル記述子のいずれかが現在使用されていない端末デバイスに向けられている場合は、スクリプトを使用して行う方が良いでしょう-他のプロセスもその端末をチェックしたいことを覚えておく必要があります。

ところで、もしあなたの目標が、私がそうであるように、スクリプトの環境をそれを実行した後に保存することであるなら、あなたはたぶんはるかに良いサービスを受けるでしょう:

. ./script

シェル.dotbash's sourceはまったく同じではありません-シェル.dotは特別なシェルビルトインとして指定されたPOSIXであるため、入手できる限り保証されていますが、これは決してそこにあるという保証ではありません...

上記は、ほとんど問題なく期待どおりに動作するはずです。たとえば、次のことができます。

 ( exec sh -i 3<<SCRIPT 4<&0 <&3                                        
    echo "do this thing"
    echo "do that thing"
    $(cat /path/to/script)
    exec  3>&- <&4
    SCRIPT
 )

シェルはスクリプトを実行し、インタラクティブプロンプトに戻ります-スクリプトからシェルを実行するexit、つまりプロセスをバックグラウンド化しない限り、i / oをリンクします/dev/null.

デモ:

% printf 'echo "%s"\n' "These lines will print out as echo" \
    "statements run from my interactive shell." \
    "This will occur before I'm given the prompt." >|/tmp/script
% ( exec sh -i 3<<SCRIPT 4<&0 <&3
    echo "do this thing"
    echo "do that thing"
    $(cat /tmp/script)
    exec  3>&- <&4
SCRIPT
)
sh-4.3$ echo "do this thing"
    do this thing
sh-4.3$ echo "do that thing"
    do that thing
sh-4.3$ echo "These lines will print out as echo"
    These lines will print out as echo
sh-4.3$ echo "statements run from my interactive shell."
    statements run from my interactive shell.
sh-4.3$ echo "This will occur before I'm given the prompt."
    This will occur before I'm given the prompt.
sh-4.3$ exec  3>&- <&4
sh-4.3$

たくさんの JOBS

シェルのビルトインタスク管理オプションについてもう少し詳しく知っておくべきだと思う。@Kiwyと@jillagreの両方は、回答ですでにこれに触れていますが、詳細を説明する必要があるかもしれません。そして、私はすでに内蔵の1 POSIX指定の特別なシェルを述べたが、きたset, jobs, fg,bg別の答えが示すように、いくつかのより多くのであり、trapそしてkillより多くの、まだ2つです。

同時実行中のバックグラウンドプロセスのステータスに関するインスタント通知をまだ受信していない場合、現在のシェルオプションがPOSIXで指定されたデフォルトのに設定されているためですが-mset -b代わりにこれらを非同期に取得できます。

% man set
    b This option shall be supported if the implementation supports the
         User  Portability  Utilities  option. It shall cause the shell to
         notify the user asynchronously of background job completions. The
         following message is written to standard error:
             "[%d]%c %s%s\n", <job-number>, <current>, <status>, <job-name>

         where the fields shall be as follows:

         <current> The  character  '+' identifies the job that would be
                     used as a default for the fg or  bg  utilities;  this
                     job  can  also  be specified using the job_id "%+" or
                     "%%".  The character  '−'  identifies  the  job  that
                     would  become  the default if the current default job
                     were to exit; this job can also  be  specified  using
                     the  job_id  "%−".   For  other jobs, this field is a
                     <space>.  At most one job can be identified with  '+'
                     and  at  most one job can be identified with '−'.  If
                     there is any suspended  job,  then  the  current  job
                     shall  be  a suspended job. If there are at least two
                     suspended jobs, then the previous job also shall be a
   m  This option shall be supported if the implementation supports the
         User Portability Utilities option. All jobs shall be run in their
         own  process groups. Immediately before the shell issues a prompt
         after completion of the background job, a message  reporting  the
         exit  status  of  the background job shall be written to standard
         error. If a foreground job stops, the shell shall write a message
         to  standard  error to that effect, formatted as described by the
         jobs utility. In addition, if a job  changes  status  other  than
         exiting  (for  example,  if  it  stops  for input or output or is
         stopped by a SIGSTOP signal), the shell  shall  write  a  similar
         message immediately prior to writing the next prompt. This option
         is enabled by default for interactive shells.

Unixベースのシステムの非常に基本的な機能は、processを処理する方法signalsです。私はかつて、このプロセスをダグラス・アダムズの「今の惑星」の説明に例える主題に関する啓発的な記事を読みました

「ギャラクシーへのヒッチハイカーのガイドで、ダグラス・アダムズは、太いで非常に激しく噛むことによって人間と通信する鋭い歯を持つたくさんの落ち込んだ人間と動物の種が生息する非常に鈍い惑星について言及します。これは驚くべきことです。 UNIXと同様、カーネルはプロセスに麻痺または致命的な信号を送信することでプロセスと通信します。プロセスは信号の一部を傍受し、状況に適応しようとしますが、ほとんどはそうではありません。

これはを参照していkill signalsます。

% kill -l 
> HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS

少なくとも私にとっては、上記の引用は多くの質問に答えました。たとえば、私は常に非常に奇妙であり、ddプロセスを監視したい場合にそれが必要であると直観的ではないと考えていましkillた。読んだ後、それは理にかなっています。

私は彼らのほとんどが正当な理由で適応しようとしないと言います-開発者があなたにとって重要だと思った情報であなたの端末をスパムするプロセスの束を持つことは恩恵よりもはるかに大きな迷惑になる可能性があります。

端末の構成(で確認できstty -aます)に応じて、現在のフォアグラウンドプロセスグループリーダー(シェルである可能性CTRL+Zが高いにaを転送するSIGTSTPように設定されている可能性がありますtrap。繰り返しますが、@ jillagreと@Kiwyの回答が示すように、この機能を好みに合わせて調整することを止めることはできません。

SCREEN JOBS

したがって、これらの機能を利用するには、まずそれらを理解し、自分のニーズに合わせて処理をカスタマイズすることが期待されます。たとえば、Githubで次のscreenキーバインドを含むこのscreenrcを見つけましたSIGTSTP

# hitting 'C-z C-z' will run Ctrl+Z (SIGTSTP, suspend as usual)
bind ^Z stuff ^Z

# hitting 'C-z z' will suspend the screen client
bind z suspend

これにより、子screenプロセスとして実行中のプロセス、またはscreen希望どおりに子プロセス自体を一時停止するのが簡単になります。

そしてその直後:

% fg  

または:

% bg

必要に応じてプロセスをフォアグラウンドまたはバックグラウンドします。jobs内蔵のは、いつでもあなたにこれらのリストを提供することができます。-lオペランドを追加すると、pidの詳細が含まれます。


とても面白そうです。今日のうちにすべてをテストすることができます。
pawel7318 14

23

以下は、あなたが望むものを達成する短いソリューションですが、問題とbashの仕組みを理解しない限り意味がないかもしれません:

bash -i <<< 'some_program with its arguments; exec </dev/tty'

これにより、bashシェルstartが起動しsome_programsome_program終了後、bashシェルにドロップされます。

基本的に私たちがしていることは、bashにSTDINの文字列を与えることです。その文字列はsome_program with its arguments; exec </dev/ttyです。これにより、bashはsome_program最初に起動してから実行するように指示さexec </dev/ttyれます。そのため、bashは文字列からコマンドを読み続ける代わりに、bashから読み始め/dev/ttyます。

これ-iは、bashが起動するときに、STDINがttyであるかどうかを確認し、起動するときはそうではないためです。しかし、後でそうなるので、強制的に対話モードにします。


別の解決策

私がそれが非常に移植性があると思った別のアイデアは、~/.bashrcファイルの最後に以下を追加することです。

if [[ -n "START_COMMAND" ]]; then
  start_command="$START_COMMAND"
  unset START_COMMAND
  eval "$start_command"
fi

次に、最初にコマンドを使用してシェルを起動する場合は、次を実行します。

START_COMMAND='some_program with its arguments' bash

説明:

これのほとんどは明らかなはずですが、変数名を変更する理由は、変数をローカライズできるようにするためです。以来$START_COMMAND、エクスポート変数であり、それはシェルの子に継承されますし、別のbashシェルは、それらの子の1つである場合には、再度コマンドを実行します。そのため、値を新しい非エクスポート変数($start_command)に割り当て、古い変数を削除します。


複数ある場合は爆発しますか?1つのコマンド?いいえ、まだ動作するはずです。ただし、移植性については正しいです。そこには2つの要素があります。それら<<<はPOSIXではありませんが、echo "string here" | bash -i代わりに可能です。それから/dev/tty、Linuxのものがあります。ただし、bashを起動する前にFDを複製してから、STDINを再度開くことができます。
パトリック14

これは私のために機能し、必要なことはすべて行います。私はPOSIXと移植性についてはあまり気にしません。私はそれを自分の箱にだけ必要とします。mikeservの回答も確認しますが、今はできません。
pawel7318 14

1
戦っていない:-)。mikservの答えを尊重します。彼は互換性のために行きました、私は単純さのために行きました。両方とも完全に有効です。複雑すぎない場合は、互換性を求めます。この場合、私はそれが価値があるとは思わなかった。
パトリック14

2
@Patrick /dev/ttyはLinuxのものではありませんが、間違いなくPOSIXです。
jlliagre 14


8

これでうまくいくはずです:

bash -c "some_program with its arguments;bash"

編集:

更新後の新しい試みは次のとおりです。

bash -c "
trap 'select wtd in bash restart exit; do [ \$wtd = restart ] && break || \$wtd ; done' 2
while true; do
    some_program with its arguments
done
"
  • 私は時々some_programを終了する必要があります

を使用するとControlC、この小さなメニューが表示されます。

1) bash
2) restart
3) exit
  • 背景に置きたくない

そうです。

  • 私はバッシュにとどまり、その後何か他のことをしたい

「bash」を選択します

  • プログラムを再度実行できるようにしたい

「再起動」を選択してください


悪くないわけではありませんが、最後のコマンドに戻ることができるのも良いでしょう。そのためのアイデアはありますか?ここで別の質問をチェックして、必要なものを確認してください。だから、多分あなたは別のアプローチを提案します
pawel7318

これにより、サブシェルが実行されます。質問者はスクリプト環境を維持しようとしていると思います。
mikeserv 14

ありがとうjlliagre-素晴らしい試みだが、私にはあまり役に立たない。私は通常ctrl + Cを押しますが、それがするはずのことをするだけだと思っています。追加のメニューは大したものです。
pawel7318 14

@ pawel7318の動作はCTRL+C、端末のデフォルト設定をとして解釈するための単なる副作用ですSIGINT。で変更することができますstty
mikeserv 14

@ pawel7318さらに明確にすること、SIGINTであるtrappedとの上2
mikeserv 14

3

スクリプトを初期化ファイルとして渡すことで実行できます。

bash --init-file foo.script

または、コマンドラインで渡すことができます:

bash --init-file <(echo "ls -al")

これ--init-fileは、システム全体の初期化ファイルを読み込む/etc/bash.bashrcためsourceのものであり、スクリプトでこれらを使用する必要がある場合があることに注意してください。


0

このプログラムを実行した後、すでにシェルに戻っているので、私はこれを行う意味が本当にわかりません。ただし、これは可能です。

bash -c "some_program with its arguments; bash"

これにより、プログラムの実行後にインタラクティブなbashが起動します。


サブシェルが起動します。
mikeserv 14

0

コマンドをバックグラウンドで実行して、現在のbashを開いたままにすることができます。

some_program with its arguments &

実行に戻るには、fgコマンドを使用^+zして、バックグラウンドに再び置くことができます


今回ではない。あなたは私がこのbashを... bashから実行したいと仮定しますが、そうではありません。
pawel7318 14

@ pawel7318もう少し詳しく説明していただければ、より良い答えが得られるかもしれません。
Kiwy 14

ここで私の別の質問をチェックしてください。
pawel7318 14

@ pawel7318質問が関連している場合は、自分の質問に他の質問へのリンクを追加してください。
Kiwy 14

1
@ pawel7318 bashかどうかにかかわらず、プロセスのバックグラウンドを処理できない場合、非常に異質なシェルを使用しています。そして、私はキウイに同意します-その情報があなたの質問にあれば、その情報はあなたにより良く役立つでしょう。
mikeserv 14

0

画面を使用してコマンドを実行することもできます。その後、コマンドの完了後にセッションに再接続できます。

または、バックグラウンドでコマンドを実行するだけsome_program with its arguments&です。これにより、コマンドを再実行し、コマンドが完了するとコマンドのステータスを取得できます。


私はそれを正確に実行していますscreenが、バックグラウンドに置くことは私にとっては役に立ちません-私は時々プログラムを終了し、何か他のことをしてからもう一度実行する必要があります。そして、主な目標はこれを迅速に行うことです。
pawel7318 14

@ pawel7318 kill %またはコマンドでバックグラウンドプログラムを強制終了できkill %1ます。
BillThor 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.