mac java呼び出し端末のいくつかの問題解決方法


最初はネットで検索してみましたが、macにはcmdがないとjavaがmacの端末をコードして呼び出すことができないという人もいましたが、後で少し試してみましたが、こんなこともあったようです.
最も簡単な、cd+パスで、ls出力します.ls出力のファイルリストが根本的にルートディレクトリであることを発見しました.つまり、前のcdコマンドは役に立たないということです.の
後で考えてみると、lsコマンドが使用できる以上、他のいくつかも使用できるはずですが、shellスクリプトを使用してjava呼び出し端末でスクリプトを開きます.shellはまず権限chmod 777パスに名前のフルネームを付けなければならない.
また、私が使いたいコマンドをshellスクリプトに書きます.さっきlsのリストは私のcdが着いたディレクトリの下にあります.ok、正常です.
gradleコマンドは、コマンドラインコンパイル生成apkに使用され、最初は、私が書いたスクリプトは直接端末にドラッグすると生成apkを実行することができますが、java呼び出し端末がスクリプトを使用するとき、仕方がありません.反応せず、出力せず...それからネットで長い間検索して、やっと私に1つの悪くない構想を発見されましたhttps://yq.aliyun.com/articles/2362ああ、この中に重要な問題が書いてあります.あなたはまたこの問題に直面するかもしれません.手作業で実行できるコマンドなのに、javaが呼び出したshellの中のいくつかのコマンドは実行できません.エラー:コマンドは存在しません.
彼はソフト接続を使うと言って、shellに触れたばかりの私に対して、ええ、ほほほ...しかし、私はずっと一方のjavaの誤った出力を忘れていることに気づいて、最初は私はただデバッグの出力をしただけで、しかし私はそれが2つのことなのか分かりません.彼のブログを見て、やっと分かりました.そして、私はずっとshellの誤った出力に考えを置いて、料理を酔いました.後で私の問題に気づいたのは、apkコンパイルを実行するとjavaポートの衝突が発生したことです.の私はideaを使用してバックグラウンドをコンパイルし、javaバックグラウンドから端末を呼び出し、自動的にapkを生成し、ideaは直接バックグラウンドを実行し、jvnを使用しました.jvnとjavaコンパイルapkが衝突するのか.のバックグラウンドはずっと開いていて、前の直接端末呼び出しスクリプトや端末直接呼び出し命令はapkを生成することができて、どうしてjava呼び出しになったら衝突しますか.のその後、私は直接warを生成してTomcatの上で実行して、それではポートを占める必要はありません.いくつかのアクティブなモニターを調べて、ポートが空いて、直接バックグラウンドを呼び出して、やっと正常にapkを生成しました.
以下、さっきのブログの内容を勝手にコピーします.
JAvaがshellを呼び出す方法
プロセスビルダーによるスケジューリング
この方法は直感的で、パラメータの設定も便利です.例えば、私が実践しているコード(ビジネスコードの一部を隠しています):
ProcessBuilder pb = new ProcessBuilder("./" + RUNNING_SHELL_FILE, param1,
                                               param2, param3);
        pb.directory(new File(SHELL_FILE_DIR));
        int runningStatus = 0;
        String s = null;
        try {
            Process p = pb.start();
            try {
                runningStatus = p.waitFor();
            } catch (InterruptedException e) {
            }

        } catch (IOException e) {
        }
        if (runningStatus != 0) {
        }
        return;

ここではいくつかのパラメータを説明する必要があります:RUNNING_SHELL_FILE:実行するスクリプトSHELL_FILE_DIR:実行するスクリプトがあるディレクトリ;もちろん、実行するスクリプトをフルパスに書くこともできます.runningStatus:運転状態、0は正常です.詳細はjavaドキュメントを参照してください.param 1,param 2,param 3:RUNNINGでできるSHELL_FILEスクリプトで直接1,2,$3でそれぞれ得られるパラメータ.
直接システムRuntimeでshellを実行
この方法は暴力的で、よく使われています.コードは以下の通りです.
p = Runtime.getRuntime().exec(SHELL_FILE_DIR + RUNNING_SHELL_FILE + " "+param1+" "+param2+" "+param3);
p.waitFor();

Runtime方式ではbuilderほど便利ではないことが分かった.特にパラメータの面では、execが文字列全体をshellとして実行するため、自分でスペースを付けなければならない.
存在する可能性のある問題と解決方法
上を通ることであなたのニーズを満たすことができると思ったら、壁にぶつかるかもしれません.次のような状況に遭遇します.
実行権限なし
この状況で私たちのチームの朱東方は出会って、DTSの移行をする過程で、パッケージの中のshellスクリプトを実行して、解凍してから、実行できないことに気づきました.では、上記の方法で授権しましょう.
ProcessBuilder builder = new ProcessBuilder("/bin/chmod", "755", tempFile.getPath());
            Process process = builder.start();
            int rc = process.waitFor();

JAvaはshellの戻りを待つ
この問題はもっとよく出会うだろう.なぜなら、shellスクリプトにechoまたはprint出力があり、バッファが切れてしまったからです.このような状況を避けるために、バッファを必ず読んで、shellの具体的な運転状態をlogすることができるというメリットがあります.例えば、上記の例では、
ProcessBuilder pb = new ProcessBuilder("./" + RUNNING_SHELL_FILE, keyword.trim(),
                                               taskId.toString(), fileName);
        pb.directory(new File(CASPERJS_FILE_DIR));
        int runningStatus = 0;
        String s = null;
        try {
            Process p = pb.start();
            BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
            BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            while ((s = stdInput.readLine()) != null) {
                LOG.error(s);
            }
            while ((s = stdError.readLine()) != null) {
                LOG.error(s);
            }
            try {
                runningStatus = p.waitFor();
            } catch (InterruptedException e) {
            }


start()の後、waitFor()の前にバッファを読み出してlogを打つと、shellが予想通りに実行されていない理由がわかります.これはshellから出力された結果を読むことができ、javaコードのさらなる操作を容易にするというメリットがあります.
手作業で実行できるコマンドなのに、javaが呼び出したshellのコマンドが実行できないという問題に直面するかもしれません.エラー:コマンドは存在しません.
例えばcasperjsを使っているとき、shellを手動で実行するのは実行できるのにjava呼び出しのとき、いつもエラーが発生していることに気づきました.バッファを読み込むことでエラーログが見つかります.インストールしたcasperjsのbinをpathに追加しても十分ではないことに気づきました(/etc/profile、各種bashrc)
export NODE_HOME="/home/admin/node"
export CASPERJS_HOME="/home/admin/casperjs"
export PHANTOMJS_HOME="/home/admin/phantomjs"
export PATH=$PATH:$JAVA_HOME/bin:/root/bin:$NODE_HOME/bin:$CASPERJS_HOME/bin:$PHANTOMJS_HOME/bin


Javaがshellを呼び出すとき、デフォルトではシステムの/bin/下の命令が使われていたからです.特にroot権限で実行しているとき.この時、あなたは/binの下にソフトチェーンを追加します.私の上記の例では、/binの下にソフトチェーンを追加します.
ln -s /home/admin/casperjs/bin/casperjs casperjs;
ln -s /home/admin/node/bin/node node;
ln -s /home/admin/phantomjs/bin/phantomjs phantomjs;

これで、問題は解決できます.
Java呼び出しshellでパッケージ化されている場合は、パスの問題に注意してください.
shellのtarの圧縮と解凍は直接書くことができません.
tar -zcf/home/admin/data/result.tar.gz/home/admin/data/result
直接エラーを報告します.tarの圧縮源はパスの下に行かなければならないので、書くことができます.
tar -zcf/home/admin/data/result.tar.gz -C/home/admin/data/result
もし私のshellがjarパッケージにいたらどうしますか?
答えは:解凍します.上記の指示に従って操作します.(1)経路を見つける
String jarPath = findClassJarPath(ClassLoaderUtil.class);
        JarFile topLevelJarFile = null;
        try {
            topLevelJarFile = new JarFile(jarPath);
            Enumeration<JarEntry> entries = topLevelJarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (!entry.isDirectory() && entry.getName().endsWith(".sh")) {
                       shell      
                }
            }

ファイルの処理方法は簡単で、直接touchの一時ファイルをtouchして、それからデータストリームを書き込んで、コード:
FileUtils.touch(tempjline);
tempjline.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempjline);
IOUtils.copy(ClassLoaderUtil.class.getResourceAsStream(r), fos);
fos.close();