# Externes Programm steuern



## nemo86 (2. Jul 2009)

Hallo,
hab folgendes Problem: unter Java muss ein Programm gestartet werden, das sich nur über bash Shell bedienen lässt. Danach muss ich ein paar Befehele, die das Programm steuren, aufrufen. Z.B. sollte folgende Codestück völlig automatisch ablaufen: 


```
$ poly
> fun f () = print "Hello World\n";
> PolyML.export("hello", f);
> ^D
$ cc -o hello hello.o -lpolymain -lpolyml
$ ./hello
```
Hab mir überlegt, dass das am besten geht, wenn ich die Befehle unter Java an bash übergebe. Nun, das Programm selbs (poly) zu starten ist kein Problem, aber wie übergebe ich weitere Befehle? (Zb fun f () = print "Hello World\n"; )


----------



## faetzminator (2. Jul 2009)

Entweder kannst du da direkt in den Channel schreiben oder die Bash bereits mit folgendem aufrufen (ungetestet):

```
$ poly | echo "fun f () = print \"Hello World\n\";\nPolyML.export(\"hello\", f);"
```


----------



## heart_disease (2. Jul 2009)

Verwende einfach den ProcessBuilder und hol dir dann den OutputStream um die Befehle an das Programm zu übergeben.


----------



## nemo86 (2. Jul 2009)

und weiter? ich meine, unter Java kann ich höchstens poly startten also:

Process p=Runtime.getRuntime().exec("poly");

weitre Eingaben, (fun f()=...) kann ich irgendwie nicht weitergeben.


----------



## Ebenius (2. Jul 2009)

nemo86 hat gesagt.:


> weitre Eingaben, (fun f()=...) kann ich irgendwie nicht weitergeben.


Doch, doch. 


```
/**
 * Test main method.
 * 
 * @param args ignored
 * @throws IOException
 * @throws InterruptedException
 */
public static void main(String[] args)
      throws IOException, InterruptedException {
  class StreamPipe implements Runnable {

    final InputStream input;
    final PrintStream output;

    StreamPipe(InputStream input, PrintStream output) {
      this.input = input;
      this.output = output;
    }

    public void run() {
      int b;
      try {
        while ((b = input.read()) != -1) {
          output.write(b);
        }
      } catch (IOException ex) {
        ex.printStackTrace();
      }
    }
  }

  final ProcessBuilder pb = new ProcessBuilder("poly");
  final Process process = pb.start();
  new Thread(new StreamPipe(process.getInputStream(), System.out)).start();
  new Thread(new StreamPipe(process.getErrorStream(), System.err)).start();

  final PrintStream stdin = new PrintStream(process.getOutputStream());
  stdin.println("fun f () = print \"Hello World\\n\";");
  stdin.println("...");
  stdin.flush();
  process.waitFor();
}
```
Ebenius


----------



## nemo86 (2. Jul 2009)

Tatsächlich danke allen für schnelle Antworten.


----------



## nemo86 (3. Jul 2009)

Beim ausführend vom Code unter Linux meldet ads Programm folgendes:


```
<pfad>: error while loading shared libraries: <irgend ein bibloithek> cannot open shared object file: No such file or directory.
```

Die Datei ist aber im Verzeichnis vorhanden. Hat jemand eine Idee woran das liegen kann?


----------



## Ebenius (3. Jul 2009)

*F*erzeichnis liest sich foll valsch. 

Shared Objects werden grundsätzlich gegen die Umgebungsvariable $LD_LIBRARY_PATH aufgelöst. Dort steht der Punkt (also das CWD) in aller Regel nicht drin. Also musst Du beim Aufruf das Environment mit passendem $LD_LIBRARY_PATH initialisieren.

... nehme ich an. 

Ebenius


----------



## nemo86 (3. Jul 2009)

Ups  Korrigiert

Ich wäre sehr dankbar, wenn du das ein bisschen ausführlicher schreibst. Wie initialisiere ich das Environment und was ist CWD? )


----------



## Ebenius (3. Jul 2009)

nemo86 hat gesagt.:


> Wie initialisiere ich das Environment [...]


Die API-Doc verrät uns das: ProcessBuilder.environment().
Letztendlich holst Du aus dem Environment die Variable, hängst einen '.' als Pfadelement an und setzt die Variable wieder: [java=33]final Map<String, String> env = pb.environment();
String envLD_LIBRARY_PATH = env.get("LD_LIBRARY_PATH");
if (envLD_LIBRARY_PATH != null && !envLD_LIBRARY_PATH.equals("")) {
  envLD_LIBRARY_PATH = envLD_LIBRARY_PATH + File.pathSeparator + '.';
} else {
  envLD_LIBRARY_PATH = '.';
}
env.put("LD_LIBRARY_PATH", envLD_LIBRARY_PATH);[/code]



nemo86 hat gesagt.:


> [...] und was ist CWD? )


Halt mal die Maus über das Wort. Moderne Browser zeigen Dir die Erklärung an (ist eine Abkürzung die "Current Working Directory" heißt).

Ebenius


----------



## nemo86 (3. Jul 2009)

hm... irgendwie macht das nicht, was es machen soll. Es wird ja ledeglich ein Punkt am Ende des Strings hinzugefügt, wo Standartbibliotheken gespeichert sind, das Bibliothek vom Programm wird weiterhin nicht gefunden....


----------



## Ebenius (3. Jul 2009)

Trag halt statt des Punktes mal den absoluten Pfad zu dem Verzeichnis ein in dem das Shared Object liegt und teste dagegen. Ggf.: schreib Dir ein kleines Bash-Skript das den LibraryPath setzt und dann _poly_ per _exec_ startet und ruf dieses Skript aus dem Java auf.

Ebenius


----------



## nemo86 (6. Jul 2009)

Vielen Dank, jetzt kalappt alles. Am Ende sieht es dann so aus:


```
class StreamPipe implements Runnable {

	final InputStream input;
	final PrintStream output;

	StreamPipe(InputStream input, PrintStream output) {
		this.input = input;
		this.output = output;
	}
	

	public void run() {
		int b;
		try {
			while ((b = input.read()) != -1) {
				output.write(b);
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
}

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Map;

public class PolyMl {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException,
			InterruptedException {

		final ProcessBuilder pb = new ProcessBuilder(
				"/usr/public/polyml-5.2.1/x86-linux/poly");

		final String nLibPath = "/usr/public/polyml-5.2.1/x86-linux";

		final Map<String, String> env = pb.environment();
		String envLD_LIBRARY_PATH = env.get("LD_LIBRARY_PATH");
		if (envLD_LIBRARY_PATH != null && !envLD_LIBRARY_PATH.equals("")) {
			envLD_LIBRARY_PATH = envLD_LIBRARY_PATH + File.pathSeparator
					+ nLibPath;
		} else {
			envLD_LIBRARY_PATH = nLibPath;
		}
		env.put("LD_LIBRARY_PATH", envLD_LIBRARY_PATH);

		final Process process = pb.start();
		new Thread(new StreamPipe(process.getInputStream(), System.out))
				.start();
		new Thread(new StreamPipe(process.getErrorStream(), System.err))
				.start();

		final PrintStream stdin = new PrintStream(process.getOutputStream());
		stdin.println("fun f () = print \"Hello World\\n\";");
		stdin.println("...");
		stdin.flush();
		process.waitFor();
	}

}
```


----------

