質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

sh

shは、UNIX系OSのシェル操作の1つであり、最も基本的なシェルのことです。

Q&A

解決済

2回答

1315閲覧

Java処理でシェルスクリプトを実行してJavaプロセスの再起動を行いたい(起動で完了)

FUJITOMO37

総合スコア25

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

UNIX

UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

sh

shは、UNIX系OSのシェル操作の1つであり、最も基本的なシェルのことです。

0グッド

0クリップ

投稿2022/11/30 08:29

編集2022/12/05 02:11

前提

javaを実行するのは、Unix環境です。

実現したいこと

javaの処理でシェルスクリプトを実行して、javaプロセスを再起動させたいです。
再起動は、起動で完了する必要があります。
プロセスが停止するとそのあと行いたい起動処理が中断されます。
Java処理AからJavaAプロセスを再起動するシェルスクリプトを実行したい。
Java処理AからJavaBプロセスを再起動するシェルスクリプトを実行したいではないです。

発生している問題・エラーメッセージ

シェルスクリプトで行うjavaのプロセス再起動時にプロセスが停止されると後続の処理も中断される。起動処理が中断されている。
シェルスクリプト実行は下記リンク先を参考。
https://takami-hiroki.hatenablog.com/entry/20101221/p1

該当のソースコード

Java

1public static void main(String[] args) { 2 try { 3 Runtime runtime = Runtime.getRuntime(); 4 Process p = runtime.exec("sh test.sh"); 5 //Process p = runtime.exec("sh test.sh &"); 6 //p.waitFor(); 7 } catch (IOException ex) { 8 } 9}

test.sh

1kill [JavaプロセスID] 2 3while true 4do 5 result=`pidin | grep java_process` 6 echo ${#result} 7 if [ ${#result} -eq 0]; then 8 break 9 fi 10 sleep 1 11done 12 13sh test_open.sh #このファイルはjavaのプロセスを起動する物です。この内容は秘密になっています。申し訳ありません。

試したこと

バックグラウンド処理とp.waitFor();を外しても同じ結果でした。

補足情報(FW/ツールのバージョンなど)

Javaのバージョン 8

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Crimson_Tide

2022/11/30 08:59

質問欄にtest.shの掲載もお願いします > javaの処理でシェルスクリプトを実行して、javaプロセスを再起動させたいです。 javaの処理 をA.java 再起動させたいjavaプロセス B.java として、A.javaとB.javaは関係のない別物でしょうか? それともB.javaはA.javaの実行プロセスでしょうか? 別のアプローチがあるかもしれません、javaプロセスを再起動させたい背景・理由を教えてください。
FUJITOMO37

2022/12/01 01:12

Crimson_Tideさん ご指摘ありがとうございます。 test.shについて掲載しました。 A.javaからシェルスクリプトを実行してA.javaを再実行したいです。 javaプロセスを再起動させたい背景・理由はファイルを削除した時に、javaプロセスをが握っているファイルだと機器の容量が削除前から変更されない問題があります。 その為、ファイル削除後にjavaプロセスの再起動が必要となっています。
syoshinsya-

2022/12/01 01:19

再起動とおっしゃっていますが、プロセスAの実行ファイル(a.jarなど)をプロセスAから起動後に、プロセスAを終了ではだめなのでしょうか
FUJITOMO37

2022/12/01 01:28

shiketaさん ご回答ありがとうございます。 試しましたが、同じ現象となりました。 ※&を付けないと停止処理もされなかったです。  下記で停止処理までは動作していました。  `runtime.exec("sh nohup test.sh &");`
FUJITOMO37

2022/12/01 01:32

syoshinsyaさん ご質問ありがとうございます。 最後は起動にする必要があります。。申し訳ありません。。
dameo

2022/12/01 08:19

まずlinux環境限定ならsetsidというコマンドでプロセスグループを新しく作れますよ。もし子プロセスから送ったシグナルが自分に帰ってきてるために停止しているなら、これが使えるように思います。 あと子プロセスの標準入出力は親のJavaプロセスとリダイレクトで繋がっているため、親側で授受しなかったり、終了してしまう前提なら使わないようにしないといけなかったように思います。
Crimson_Tide

2022/12/01 11:13 編集

test.sh掲載ありがとうございます。 これオリジナルの全文でしょうか?一部抜粋なり変更していますか? 公にできない記述などの変更は必要ですが、問題点が見えなくなる可能性があるのでオリジナルからの変更は最低限でお願いします。 Bourne Shell得意じゃないので、 (動作に影響ないですが)resultじゃなくてresyltの箇所があったり、 変数の参照に#がつくのはいいのか while,untilやforなしでdo doneだけでループするのか などが問題なく動作するのか判断つかないですが、単体で動作テストしているでしょうか? Javaからじゃなく、外から(プロンプトなどから)test.sh(test_open.shも)を起動して正常に実行できるか確認していますでしょうか? ubuntuで試した限りではdo done の冒頭でSyntax error: "do" unexpectedでエラーで処理が止まりました。test.shの構文ミスで処理が途中で止まっている可能性がないかと考えています。 あとOSを教えてください。
syoshinsya-

2022/12/01 11:40

test.shを見ていて思ったのですが、killしているから >シェルスクリプトで行うjavaのプロセス再起動時にプロセスが停止されると後続の処理も中断される。起動処理が中断されている。 となってしまうのでは... java実行中にシェルスクリプトを呼ぶわけで、そこで実行元のプロセスキルしたらその後の処理中断されるよね
Crimson_Tide

2022/12/02 04:20 編集

シェルスクリプトのエラーの有無関係なしに、KILL投げると確かにシェルスクリプトも終了しているように見受けられますね。 setsidで試してみましたが自分の環境では、同様の結果でした。 setsid 、nohupで実行したシェルスクリプトでも親プロセスはJavaでした。 ちなみに、同じJava内から実行した別のシェルスクリプトはJavaがKILL受けてもJava実行の上位プロセス下で動き続けています。 PPIDがJavaではない別プロセスで実行できればいけないかな、と考えてますが実現可否は不明。 (当初上記コメントsetuidと誤記していました。setsidの誤りでしたので修正しています)
dameo

2022/12/02 02:31

setsidはプロセスグループを新しく作る=親プロセスを自分にして引数で指定されたコマンドを実行するコマンドです。多分Linux限定ですが。
FUJITOMO37

2022/12/02 04:41

dameoさん 色々とご回答頂きありがとうございまず。 しかし、OSはUNIXのQNXというものでsetsidが対応していない様です。。 申し訳ありません。。
Crimson_Tide

2022/12/02 04:43

上記コメントsetuidと誤記していました。setsidの誤りでしたので修正しました。 またsetsidを試した際、オプションなしで実行してしまいましたが、-fオプションをつけることで親プロセスがJavaを実行したプロセスからJavaの2つ上位のプロセスに変更されました。 オプションなしsetsid (PGIDは新規) PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 7334 159457 159457 7334 pts/4 159457 Sl+ 1000 0:00 java Java_iotgateway 159457 159479 159479 159479 ? -1 Ss 1000 0:00 /usr/bin/sh /home/user/dev/test.sh -f オプションありsetsid (プロセス名の\_ はツリー表示によるもの) 7332 7333 7332 7332 ? -1 S 0 0:00 \_ /init 7333 7334 7334 7334 pts/4 157230 Ss 1000 0:00 \_ -bash 7334 157230 157230 7334 pts/4 157230 Sl+ 1000 0:00 | \_ java Java_iotgateway 7333 157253 157253 157253 ? -1 Ss 1000 0:00 \_ /usr/bin/sh /home/user/dev/test.sh ただ-fつけた場合でもKILL投げた後にシェルスクリプトは終了していました (シェルスクリプト内のKILLの後続のログ出力処理が行われていないことから判断)
dameo

2022/12/02 04:58 編集

@FUJITOMO37 RTOSならむしろスクリプトが邪道かと…その辺は自分でsedsid()を使うしか。 https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/s/setsid.html ある程度大きなものでJavaやスクリプトを常用しているのでしょうけど、足りないコマンドくらい自分で作れないと思ったことをできない気がします。ただそもそも親子関係が基本的に逆だと思うんですけどね。 @Crimson_Tide コードを示しましょう。再現できない話は原因が違っていても気付くことができません。
FUJITOMO37

2022/12/02 04:58

Crimson_Tideさん test.shの内容に誤記がありました。。申し訳ありません。。 修正しました。 OSはUNXのQNXです。 こちらではsetsidが使用できない様です。。申し訳ありません。。 プロンプトからtest.shとtest_open.shの実行はエラー無く可能です。
FUJITOMO37

2022/12/04 07:28

dameoさん ご回答ありがとうございます。 返信が遅くなり申し訳ありません。 cについては知識がないですが、問題が発生するOSにはccやgccが入ってないようです。 当たり前かもしれないですが、wslでコンパイルしたものは動作しません。 Unixエミュレーターでコンパイルしたものが動作するか確認してみます。
FUJITOMO37

2022/12/04 07:48

ご教授頂き、ありがとうございます。 ご回答、感謝いたします。 自分が組み込み系の開発が初でして。。 他メンバーの方もなかなか捕まえれないので助かりました。 結果は報告致します。
dameo

2022/12/04 08:07

ここで聞いてしまっている時点でかなり問題ですが、Javaにしてもshell scriptにしてもCにしても、とてもじゃないけど業務で使えるレベルじゃありません。 保証金積んででも今すぐお断りすることをオススメします。
FUJITOMO37

2022/12/04 08:12

知識不足で申し訳ありません。。 出来る限りの事はやってみますので。。 ご協力感謝いたします。
guest

回答2

0

とりあえずコメントに書いた内容のものを参考までに貼っておきます。java Sample 1みたいな感じで実行すると、起動したプロセスはすぐ終了しますが、バックグラウンドでjava Sampleが動いてます(ビジーループ)。Linuxのようなsetsidコマンドがある環境でないと動作しません。

Sample.java

Java

1class Sample { 2 public static void main(String[] args) { 3 try { 4 Runtime runtime = Runtime.getRuntime(); 5 runtime.addShutdownHook(new Thread(()->System.out.println("shutdown!!!"))); 6 if (args.length > 0) { 7 Process p = runtime.exec("sh test.sh"); 8 p.waitFor(); 9 System.out.println(p.exitValue()); 10 } 11 System.out.println("busy loop!"); 12 while (true); 13 } catch (Exception ex) { 14 ex.printStackTrace(System.err); 15 } 16 } 17}

test.sh

bash

1PPID=$(ps -o pgid= "$$" 2>/dev/null | sed -r 's/^\s+//') 2if [ "$$" != "$PPID" ]; then 3 exec setsid sh $0 $PPID 4fi 5kill $1 6java Sample&

投稿2022/12/01 15:31

編集2022/12/01 15:32
dameo

総合スコア943

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syoshinsya-

2022/12/02 02:18

javaの方で自分のPID取得できますよ
dameo

2022/12/02 02:29

それは分かるのですが、一応Javaはプラットフォーム依存のコードは書かない方がいいので。 PPIDを引数で渡しているのは、execという現プロセスのまま新しいイメージで上書き実行できる特殊なコマンドでsetsidを実行し、その中でさらにshを実行しているからです。bourne shell系だとexportしていないシェル変数PPIDは引き継がれないので引数で渡す感じです。setsidで実行したshは新しいプロセスグループ=親プロセスが自分になります。
guest

0

ベストアンサー

ファイルの削除をしたいということだったのでプロセス管理用のjarファイルとファイル削除用のjarファイルを用意すればいいのかなと思いました。

処理の流れは

  1. 空き容量を確認
  2. ゴミファイルの生成
  3. 空き容量を確認
  4. ゴミファイルの削除
  5. 空き容量を確認

となっております

ちなみにですが、file_delete_test.jar単体でテスト稼働(ゴミファイルの生成から削除まで)をした際には、プロセスを再起動しなくても空き容量は削除後のものが読み取れましたよ

ProcessManager.java

java

1public class Main { 2 public static void main(String[] args) throws IOException, InterruptedException { 3 String resultCode = "1"; 4 Runtime r = Runtime.getRuntime(); 5 File file = new File("/"); 6 7 //空き容量を確認 8 long total = file.getFreeSpace(); 9 System.out.println(total + "byte"); 10 System.out.println(total / 1024 / 1024 / 1024 + "Gb"); 11 12 do{ 13 Process p = r.exec("java -jar file_delete_test.jar " + resultCode); 14 15 //上のプロセスからの出力を読み取り 16 InputStream inputStream = p.getInputStream(); 17 InputStreamReader inputStreamReader = new InputStreamReader(inputStream); 18 BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 19 p.waitFor(); 20 resultCode = bufferedReader.readLine(); 21 bufferedReader.close(); 22 inputStreamReader.close(); 23 inputStream.close(); 24 25 //空き容量を確認 26 total = file.getFreeSpace(); 27 System.out.println(total + "byte"); 28 System.out.println(total / 1024 / 1024 / 1024 + "Gb"); 29 }while (!resultCode.equals("3")); 30 } 31}

FileDeleteTest.java

java

1public class Main { 2 public static void main(String[] args) throws IOException { 3 String workingDir = System.getProperty("user.dir") + "/"; 4 5 if (args.length != 1) { 6 System.out.println("1"); 7 System.exit(0); 8 } 9 10 switch (args[0]) { 11 case "1": 12 //ゴミデータの生成 13 new FileCreate(workingDir).makeDemoFile("demo.json", 10000000); 14 System.out.println("2"); 15 break; 16 17 case "2": 18 //ファイル削除 19 Files.delete(Path.of(workingDir + "demo.json")); 20 System.out.println("3"); 21 break; 22 23 default: 24 System.out.println("1"); 25 break; 26 } 27 System.exit(0); 28 } 29}

投稿2022/12/01 11:46

syoshinsya-

総合スコア21

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

FUJITOMO37

2022/12/02 05:00

syoshinsyaさん コード記載ありがとうございます。 しかし、javaプロセスを別に作成するのは極力避けたい方針のようでして。。 申し訳ありませんが、当分はUNIXコマンド等で解決法がないか調査致します。
FUJITOMO37

2022/12/26 10:16 編集

別途javaプロセス作成は禁止されましたが、シェルスクリプトで別途監視処理プロセスを作る事で解決しました。 ファイルが削除されたら処理を開始する様にしてます。 こちらのご提案がヒントとなりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問