Aufruf von Batch / cmd Dateien

takidoso

Erfahrenes Mitglied
Hallo und Halli,
eigentlich dachte ich das Problem nicht zu haben, doch langsam bin ich am Verzeifeln

Folgende Szene:
Eine Java-Appliation soll CMD-Skripte aufrufen können, die mittels Konfiguration ihr bekanntgegben werden.
Normalerweise klappte dass auch doch nun stelle ich fest dass es offenbar hängen bleibt in folgenden Fällen

Wenn REM (ein kommentar eingestellt ist)
hat das Sciptfile folgenden Inhalt
Code:
echo on
copy %1 %2
copy %1 %3
wobei die Paramter mittels Konfiguration gefüllt werden, klappt es prima!
ist der code aber so etwas:
Code:
REM ******************************
REM bla bla 
REM ******************************
echo on
copy %1 %2
copy %1 %3
wird das script nicht ausgeführt, obgleich es in einem Komandozeilenfenster problemlos läuft.

in folgendem Fall wo ich nun extra schon die Kommentare rausgenommen hatte

Code:
echo on
copy %1 %2
SET KEYTOOLX=C:\Programme\Java\jdk1.5.0_14\bin\keytool.exe
%KEYTOOLX% -genkey -keyalg RSA -keysize 2048 -alias %4 -keypass MyPrivateKeyPassword -keystore %3 -storepass MyKeyStorePassword -validity 365 -dname "CN=FileDemon,OU=IT Infrastructure,O=Equens AG,L=Frankfurt,ST=Hessen,C=de"
%KEYTOOLX% -selfcert -alias %4 -sigalg SHA1withRSA -keypass MyPrivateKeyPassword -keystore %3 -storepass MyKeyStorePassword -validity 365
%KEYTOOLX% -export -alias %4 -file %5 -keystore %3 -storepass MyKeyStorePassword
copy %5 %6
und das ganze dann auch bei der Konfiguration folgendermaßen aufgerufen wird:
Code:
cmd /c scripts\windows\takegencerti.cmd from_\x.AGRSPO001F.CERTI.0300.20090522161500.00001 interim\tmp.certi_5503.der interim\tmp.FDKeyStoreTest.jks fdkey interim\tmp.MyCertificate.der.4u interim\tmp.MyCertificate.der.4me
bleibt er bei der Schlüsselgenerierung offenbar stecken und verharrt, obwohl wiederum innerhalb eines Kommandozeilenfensters es problemlos funktioniert.

Hat da jemand zufällig eine Idee woran es liegen könnte bzw. wie man weiteres überprüfen könnte?

Der Java-Code, der schließlich den Kram aufruft sieht so aus:
Java:
    /**
     * starts an application either by OS-Call or by an java class included in class path
     *
     * @param iFile
     * @param outFileNameDateMap
     * @param commandPatStr
     * @param className4Call
     * @param props4Call
     * @return Object[2] while [0] (String)   originalFileName that is IFile.getName() without prefix
     *                         [1] (String[]) replaceTokens (Tokens that are used in the command or appl call that were replaced)
     * @throws Exception
     * @see getTokensToReplace(String)
     * @see getTokensToReplace(Properties)
     */
    public Object[] startApplication(File iFile,
                                     Map<String,List<OutputFileInfos>> outFileNameDateMap,
                                     Map<String,String>                otherStringMap,
                                     String commandPatStr,
                                     String className4Call,
                                     Properties props4Call) throws Exception
    {
        String[] replaceTokens;

        String originalFileName = iFile.getName();

        if (originalFileName.substring(0,m_config.getInputFileNameReservedPrefix().length()).equals(m_config.getInputFileNameReservedPrefix()))
        {
            originalFileName = originalFileName.substring(m_config.getInputFileNameReservedPrefix().length()); // get rid of prefix
        }

        if (commandPatStr!=null && commandPatStr.length() > 0)
        {//call application by OS
            replaceTokens = getTokensToReplace(commandPatStr);

            subsituteOtherStrings(originalFileName, replaceTokens, otherStringMap);
            generateTmpOutputFileNames(originalFileName, replaceTokens, outFileNameDateMap);

            String applCall = generateApplCall(commandPatStr, replaceTokens, iFile.getName(), outFileNameDateMap, otherStringMap);
            //**************************************
            System.out.println(applCall);
            System.out.println("File:"+iFile.getAbsolutePath()+"\n   exists:"+iFile.exists());
            //**************************************
            String [] toks = applCall.split(" ");
            for (String tok :toks)
            {
                System.out.println("'"+tok+"'");
            }

            ProcessBuilder pb = new ProcessBuilder(toks);

            Process p = pb.start();
            if (p.waitFor()!=0)
            {
                throw new RuntimeException("OS-call '"+applCall+"' returned "+p.exitValue()+
                                           "\nso xml-services for output, output-backup, renaming output"+
                                           "\nhas not been executed; input-file has not been deleted as well!");
            }

        }
        else
        {//call application by Java-class

            replaceTokens = getTokensToReplace(props4Call);

            subsituteOtherStrings(originalFileName, replaceTokens, otherStringMap);
            generateTmpOutputFileNames(originalFileName, replaceTokens,  outFileNameDateMap);

            // produce every time a new applRunner since the init could be incomplete or unsafe
            RunnableByProperties applRunner;
            applRunner = (RunnableByProperties) Class.forName(className4Call).newInstance();

            applRunner.init(generateResolvedProperties(replaceTokens, iFile.getName(), outFileNameDateMap, otherStringMap));
            applRunner.run();
        }


        return new Object[] {originalFileName, replaceTokens};
    }
wobei hier eigentlich nur {//call application by OS ...} interessant ist.

Für weiterfürhende Tips bin ich glücklich und dankbar :)

Takidoso
 
Also ohne groß deinen Code angeschaut zu haben, Batch-Files haben meistens wie gewünscht funktioniert wenn ich sie über cmd.exe gestartet habe, zB:

Code:
cmd /C C:\Temp\test.bat
 
Hi Billie,
das hatte bei mri sonst auch funktioniert, auch wenn ich es mit kleinem c und nicht großen C als option verwendet hatte. Ich habe spaßeshalber es auch mit einem großen C ausprobiert. Resultat ist das selbe :-(
Zwischenzeitlich hatte ich auch versucht ob ich Standard-ausgabe umbiegen kann, aber irgendwie ohne erfolg.
Kann es sein dass es an den Ausgaben liegt?


Nachtrag: Scheinen tatsächlich die Ausgaben zu sein, ich habe jetzt mal ein echo off reingebracht und ...
schon funktioniert es auch :-/
Gibt es da eine elegante Lösung Auch Skripte mit Ausgaben erfolgreich durchlaufen zu lassen?
 
Zuletzt bearbeitet:
Hi.

Das Problem sind die Ausgaben. Der Ausgabepuffer wird gefüllt und das aufgerufen Programm kann nicht weiterarbeiten bis der Ausgabepuffer geleert wird.

Wenn dich die Ausgaben nicht interessieren (und du auch keine Eingabe vornehmen willst) dann schließe mal alle 3 Streams des Prozesses.

Gruß
 
Ich habe jetzt mal kurz for dem waitfor alle drei Standardstreams geschlossen.
Nun bekomme ich jedoch eine 1 als return code. Offenbar mag das das Skript nicht, wenn man seine Standardstreams schließt und man echo auf on stellt.
Wie müsste es denn aussehen, wenn man die Ausgaben z.B. in eine Datei stellen wollte? gibt es dazu ein schönes Codebeispiel?


Nachtrag: offenbar hat er einen returncode 1 ausgespuckt wegen des geschlossenen InputStreams. wenn ich nur Standardausgabe und Error-Stream schließe geht er wieder in ewiges Hängen über.
 
Zuletzt bearbeitet:
Bzgl. Streams in Datei umleiten, das funktioniert auch in Windows wie folgt gut:

Code:
cmd /C C:\Temp\test.bat > C:\Temp\test.log 2>&1

Du kannst auch alles im Nirvana verschwinden lassen, zB:

Code:
cmd /C C:\Temp\test.bat > NUL 2>&1

od. die Ausgabe an die Datei anhängen anstatt neu zu schreiben:

Code:
cmd /C C:\Temp\test.bat >> C:\Temp\test.log 2>&1

Übrigens, 1 ist der "Standard-Stream" und 2 der ErrorStream ... also 2>&1 bedeutet leite ErrorStream in Standard-Stream um (System.out und System.err).
 
Danke für die nette Beihilfe.
der Link von torax13 ist prima, er erklärt auch über welche Fallen man sonst noch stolpern kann, z.B. dass ein Redirect nicht so ohne weiteres dazutun nicht funktioniert, da es bei dem Aufruf von processBuilder bzw RunTime.exec(...) eben nicht um ein eins zu eins Kommand-Line-Interface handelt.

Der unter dem Link von torax13 Code für den StreamGobbler habe ich mal modifiziert ausprobiert, wobei mir auffiel, dass man den Ridirect besser nicht auf Standardausgabe geben sollte, da sonst irgendwie die anderen Standard-Ausgaben nach einer Zeit flöten gehen. Habe dazu leider noch keine Lösung finden können.

Des Weiteren fiel mir auf, dass drolligerweie Keytool nach erzeugen eines Zertifikates in Standard-Error ausschreibt, es habe ein Zertifikat erstellt.

Würde mich echt interessieren woran das liegten könnte!

ansonsten scheint es nun zu klappen.
 
Zurück