externes Shell-Script aus Java starten

GBunge

Mitglied
Thread Starter
Dabei seit
11.11.2008
Beiträge
74
Reaktionspunkte
1
Hallo Mac-User,
aus einer Java-Applikation möchte ich ein Shell-Script starten. Dazu habe ich mir ein Testprogramm geschrieben.
Java:
package skripttester;

import java.io.*;

public class SkriptTester {

    public static void main(String[] args) {
        // Pfad zum Skript
        String path = System.getenv("HOME")+"/bin/applefotos.sh";
        // Skript Ausführbarkeit testen
        if( !new File(path).canExecute()){
            System.out.println( path + " kann nicht ausgeführt werden!");
            return;
        }
        // Processbuilder und Process Instanzen
        ProcessBuilder procBld = new ProcessBuilder( path, "" );
        Process proc = null;
        // Process starten
        try {
            proc = procBld.start();
            int status = proc.waitFor();
            // Rückgabewert
            System.out.println("Exit status: " + status );
        }
        catch (IOException | InterruptedException e) { e.printStackTrace(); }
        System.out.println("Prgrammende!" );
    }
}

Das Script liegt an anderer Stelle im Dateibaum uns sieht so aus.
Bash:
#Fotos der App 'Apple-Fotos' in den Ordner 'AppleFotos' kopieren
#!/bin/sh
pwd
cd /Users/gb/Pictures/"Photos Library.photoslibrary"/originals/
pwd
echo .
echo "das hat geklappt!"
echo .
cp -R * /Users/gb/AppleFotos
exit 0
Hier nun mein Problem:
Das Java-Programm startet das Skript.
Der zurück gegebene Status ist 0.
Allerdings wird nur der Shellbefehl 'cd' ausgeführt.
Der Copy-Befehl 'cp -R' wird nicht ausgeführt.

Starte ich das Script im Terminal, dann wird der Copy-Befehl ausgeführt und die Fotos kopiert.

Woran kann das liegen? Ich bin mit meinem Latein am Ende.

Gruss GBunge
 
Mit welchem User wird das Shell Script ausgeführt?
Hat der Schreibrechte auf das Verzeichnis?
Vielleicht auch mal whoami ins Script
 
  • Gefällt mir
Reaktionen: dg2rbf
Mit welchem User wird das Shell Script ausgeführt?
Hat der Schreibrechte auf das Verzeichnis?
Vielleicht auch mal whoami ins Script
Hallo oneOeight,
die Zugriffsrechte stimmen. Das Script ist ausführbar und gehört mir.
Code:
-rwxr-xr-x@ 1 gb  staff  909 13 Aug 16:22 applefotos.sh
Ich habe auch schon probiert, ob es an NetBeans liegt, und das
JAR-File ausserhalb NetBeans im Terminal gestartet, funktioniert.
Es war das gleiche Verhalten. Keine Ausführung des Copy-Befehls.
GBunge
 
Allerdings wird nur der Shellbefehl 'cd' ausgeführt.
Der Copy-Befehl 'cp -R' wird nicht ausgeführt.

Woher weißt du das? Du redirect'est doch gar nicht den Shell Output zurück, oder? Hast du überhaupt Output aus dem Skript? oO(Ich vermute hier nur, java ist schon etwas her, ..).

Wenn das cd nicht klappt, funktioniert das cp logischerweise auch nicht, und du hast quasi keinen Effekt. Du gibst ja selbst den exit status vor, nämlich 0 (alles in Ordnung). Der hat somit keine Aussage.


Also:

1) Was ist denn der Logoutput von dem Script? Siehst du den? Kannst du den mal posten?
2) Ansonsten, output redirected. Script ausführen mit

Code:
set -x
und/oder
Code:
set -e

Code:
help set

Code:
      -e  Exit immediately if a command exits with a non-zero status.
      -x  Print commands and their arguments as they are executed.

set -x sagt dir genau, was das script macht. Schritt für Schritt. Dann musst du keine eigenen "debug logs" einbauen. Das whoami von oneOeight ist auch ne gute Idee. Das würd ich noch dazu packen.
 
Zuletzt bearbeitet:
Woher weißt du das? Du redirect'est doch gar nicht den Shell Output zurück, oder? Hast du überhaupt Output aus dem Skript? oO(Ich vermute hier nur, java ist schon etwas her, ..).

Wenn das cd nicht klappt, funktioniert das cp logischerweise auch nicht, und du hast quasi keinen Effekt. Du gibst ja selbst den exit status vor, nämlich 0 (alles in Ordnung). Der hat somit keine Aussage.


Also:

1) Was ist denn der Logoutput von dem Script? Siehst du den? Kannst du den mal posten?
2) Ansonsten, output redirected. Script ausführen mit

Code:
set -x
und/oder
Code:
set -e

Code:
help set

Code:
      -e  Exit immediately if a command exits with a non-zero status.
      -x  Print commands and their arguments as they are executed.

set -x sagt dir genau, was das script macht. Schritt für Schritt. Dann musst du keine eigenen "debug logs" einbauen. Das whoami von oneOeight ist auch ne gute Idee. Das würd ich noch dazu packen.
Hallo xentric,
habe Deinen Rat befolgt. Das Ergebnis beim Ausführen des ShellScripts im Terminal:
Code:
gb-$: ./bin/applefotos.sh
+ whoami
gb
+ pwd
/Users/gb
+ cd '/Users/gb/Pictures/Photos Library.photoslibrary/originals/'
+ pwd
/Users/gb/Pictures/Photos Library.photoslibrary/originals
+ cp -R 0 1 2 3 4 5 6 7 8 9 A B C D E F /Users/gb/AppleFotos

Das Programm in NetBeans gestartet ergibt auf der NetBeans-Console folgenden Output:
Java:
run:
Exit status: 1
Prgrammende!
BUILD SUCCESSFUL (total time: 0 seconds)
Der Process-Status ist 1, nachdem ich den Befehl 'exit 0' im Script gelöscht habe.
Das der Befehl 'cp -R ..' nicht ausgeführt wird, kann man am leeren Zielordner sehen.
 
Kannst du mit echo was in der Netbeans Konsole ausgeben?
Dann dort das whoami ausgeben, sonst in eine Datei schreiben.
 
Warum wechselst du eigentlich in das Shell Skript? Die Files API von Java ist doch seit Jahren wirklich komfortabel. Dann könntest du alles im Debugger sehen...
 
ich würde mal das java Programm so umschreiben, dass man out & err sieht. geht z.b. so:
// Processbuilder und Process Instanzen
ProcessBuilder procBld = new ProcessBuilder( path, "" );
Process proc = null;
// Process starten
try {
proc = procBld.start();
byte[] buff = new byte[1024];
int len = 0;
InputStream out = proc.getInputStream();
while ( (len=out.read(buff)) > -1 ) {
System.out.print(new String(buff, 0, len));
}
InputStream err = proc.getErrorStream();
len = 0;
while ( (len=err.read(buff)) > -1 ) {
System.out.print(new String(buff, 0, len));
}
int status = proc.waitFor();
// Rückgabewert
System.out.println("Exit status: " + status );
}
catch (IOException | InterruptedException e) { e.printStackTrace(); }
System.out.println("Prgrammende!" );
ich würde auch die erste Zeile im shell script nicht mit einem Kommentar beginnen. die erste Zeile sollte die shebang sein. das ist jetzt nicht tragisch, aber ich würde es trotzdem nicht machen.

wie schon gesagt, würde ich immer set +eu in shell Skripten setzen. das kann ich nur unterstreichen.

Außerdem ist (in 2021 praktisch überall) bash installiert. daher lieber "#!/usr/bin/env bash" als shebang nehmen und dann das script in bash anstatt in sh schreiben.

Ich habe dein Script mal getestet und das klappt bei mir (ohne Veränderungen bis auf /home/gb zu /home/oli).

Ich würde mal das "cp ...." mit einem "find ." ersetzen und schauen ob das klappt.
 
  • Gefällt mir
Reaktionen: ruerueka
Der Aufwand lohnt sich aber nur, wenn bestehende und sehr umfangreiche Skripte eingebunden werden sollen, z.B. auch welche, die von anderen Menschen gepflegt werden. Das Problem, dass die IDE keinen vollständigen Terminal bereitstellt, bleibt aber. Da ist testen von der Kommandozeile besser. Ist kein Problem zb mit Maven basierten Projekten.
Für die konkrete Aufgabe würde ich das aber direkt in Java machen, hier ein Beispiel direkt aus der Doku von Oracle:
https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileVisitor.html
 
Er muss doch nur noch den Output des Skripts zurück in die Javaanwendung leiten und ausgeben. Das ist das, was ich mit "redirect" meinte. Entweder so wie oglimmer vorschlägt, oder anscheinend geht das mit Java 7/8 auch einfach durch: inheritIO()/redirectOutput()/getInputStream().

https://stackoverflow.com/questions/16714127/how-to-redirect-processbuilders-output-to-a-string

Oder wie schon vorgeschlagen alternativ in eine Datei ausgeben über das Skript selbst.

Das sind doch beides nur noch ein paar Zeilen.

Ich vermute nämlich auch wie oneOeight, dass der Javaprozess keine Rechte hat, und dadurch das working dir ganz woander ist. Nur das Skript einzeln ausführen zur Kontrolle bringt jedenfalls nichts. Und aktuell verpasst du die Skriptausgabe, wenn du es über deine Javaanwendung ausführst.

Bin mir sicher, wir alle die geantwortet haben, verstehen das. Wollte das nur nochmal zusammenfassen für GBunge.
 
  • Gefällt mir
Reaktionen: ruerueka
Alternativ kann er ja mal dem Zielordner ein chmod o+w verpassen, ob es dann klappt.
 
Hallo alle die sich soviel Gedanken über mein Problem gemacht haben!
Ich werde die nächsten Tage zutun haben, alles auszuprobieren.
Meiner Meinung nach hat der Beitrag von oglimmer
ich würde mal das java Programm so umschreiben, dass man out & err sieht. geht z.b. so:

ich würde auch die erste Zeile im shell script nicht mit einem Kommentar beginnen. die erste Zeile sollte die shebang sein. das ist jetzt nicht tragisch, aber ich würde es trotzdem nicht machen.

wie schon gesagt, würde ich immer set +eu in shell Skripten setzen. das kann ich nur unterstreichen.

Außerdem ist (in 2021 praktisch überall) bash installiert. daher lieber "#!/usr/bin/env bash" als shebang nehmen und dann das script in bash anstatt in sh schreiben.

Ich habe dein Script mal getestet und das klappt bei mir (ohne Veränderungen bis auf /home/gb zu /home/oli).

Ich würde mal das "cp ...." mit die besten Chanceneinem "find ." ersetzen und schauen ob das klappt.
die größte Chance das Problem näher ein zukreisen.

Ich will hier nochmal posten, warum der ganze Aufwand:
Ich möchte die Images von Apple-Fotos auf Dublikate untersuchen.
Dazu benutze ich File.listFiles() und das gibt immer null.

Danke GBunge
 
Ich führe auch ein paar Scrips aus Java heraus aus. Nutze dafür die Runtime, vielleicht hilft es dir. Sh files sind auch kein Problem damit, Parameter wird im Array angegeben und dann mit entsprechenden Leerzeichen ausgeführt

Java:
private void rebootApp() {
        String[] command = {"systemctl", "restart", "app"};
        try {
            Runtime.getRuntime().exec(command);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Edit: grad erst gesehen, dass der Thread alt ist :p
 
Zurück
Oben Unten