Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / October 2006

Tip: Looking for answers? Try searching our database.

exec() and sending to STDIO and reading from STDIO

Thread view: 
WinstonSmith_101@hotmail.com - 17 Oct 2006 17:44 GMT
I have an external program I need to execute which takes an argument.
So I have the code:

String command = "...";
String argument = "...";
process = Runtime.getRuntime().exec(command);

And then for sending arguments:

java.io.OutputStream out = process.getOutputStream();
out.write(argument.getBytes());
out.close();

And the for reading output from the external command:

java.io.InputStream in = encryptProcess.getInputStream();
int c;
while ((c = in.read()) != -1)
{
   System.out.print("OUT: " + (char)c);
}
in.close();

= = = = = = = = = = = = = = = = = =

But the problem is that the output is not actually read. It's still
being outputted when I close the InputStream (in.close();)

Is there not a way to but execute an external program, send arguments
to it and get it's output?

I have tried to insert the command "echo argument|command" e.g.
"echo test|ls" in the command, but this merely echos out the whole
line ("test|ls") rather than sending the argument "test" to
"ls".

Thanks
/Rune
Gordon Beaton - 17 Oct 2006 18:08 GMT
> I have tried to insert the command "echo argument|command" e.g.
> "echo test|ls" in the command, but this merely echos out the whole
> line ("test|ls") rather than sending the argument "test" to
> "ls".

It's hardly meaningful to send input to ls that way, but it fails
because you are attempting to use shell features where there is no
shell. You need to do it like this:

 String[] cmd = { "/bin/sh", "-c", "echo foo | gurka" };
 Process p = System.getRuntime().exec(cmd);

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

WinstonSmith_101@hotmail.com - 18 Oct 2006 08:46 GMT
> > I have tried to insert the command "echo argument|command" e.g.
> > "echo test|ls" in the command, but this merely echos out the whole
[quoted text clipped - 7 lines]
>   String[] cmd = { "/bin/sh", "-c", "echo foo | gurka" };
>   Process p = System.getRuntime().exec(cmd);

Hello thanks for the feedback, but this merely echos out "foo | gurka".
Gordon Beaton - 18 Oct 2006 09:10 GMT
> Hello thanks for the feedback, but this merely echos out "foo | gurka".

No, it doesn't. Post your *actual* code. You are not running a shell
as I suggested.

This is what happens when I run it with real commands:

 bash$ cat Test.java
 import java.io.*;
 
 public class Test {
   public static void main(String[] args) throws Exception {
     String[] cmd = { "/bin/sh", "-c", "echo this is a test | wc" };
     Process p = Runtime.getRuntime().exec(cmd);
 
     BufferedReader br = new BufferedReader(new InputStreamReader (p.getInputStream()));
 
     String line;
     while ((line = br.readLine()) != null) {
       System.out.println(line);
     }
     br.close();
   }
 }
 
 base$ javac Test.java
 bash$ java Test
       1       4      15
 bash$
 
The example is complete and compilable. Try it.

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

WinstonSmith_101@hotmail.com - 18 Oct 2006 12:30 GMT
> > Hello thanks for the feedback, but this merely echos out "foo | gurka".
>
[quoted text clipped - 27 lines]
>
> The example is complete and compilable. Try it.

- your example works. But when I substitude the program gpg for wc, I
stop getting the output. Can it be that it sends on STDERR or
something?

import java.io.*;

public class Test1
{
   public static void main(String[] args) throws Exception
   {
       String[] cmd = { "/bin/sh", "-c", "echo mypasswd | gpg
--passphrase-fd 0 -o tobe.zip -q --decrypt tobe.zip.gpg" };

       Process p = Runtime.getRuntime().exec(cmd);

       BufferedReader br = new BufferedReader(new InputStreamReader
(p.getInputStream()));

       String line;
       while ((line = br.readLine()) != null)
       {
           System.out.println("XXX: " + line);
       }

       br.close();
   }
}

- it's the same. I just changed the "String[] cmd =" line
Gordon Beaton - 18 Oct 2006 12:59 GMT
> But when I substitude the program gpg for wc, I stop getting the
> output. Can it be that it sends on STDERR or something?

It's quite possible that gpg is sending output to stderr, but you
should be reading from both streams anyway (which my simple example
doesn't do). To do this correctly you need to read from the error
stream from a separate thread.

An alternative is to to use ProcessBuilder, which can combine both
streams into one and you don't need any extra thread. But since you're
using a shell anyway, you can make a simple change to the command and
it will combine the output streams for you:

String[] cmd = {
   "/bin/sh",
   "-c",
   "echo mypasswd | gpg --passphrase-fd 0 -o tobe.zip -q --decrypt tobe.zip.gpg 2>&1"
 };

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

aeonsun - 20 Oct 2006 08:45 GMT
how can i reading from stdio use this command:
type mytest.txt                    (win32)

use String[] cmd = {"cmd","/c","type mytest.txt"} ,it dosn't work.
Gordon Beaton - 20 Oct 2006 09:11 GMT
> how can i reading from stdio use this command:
> type mytest.txt                    (win32)
>
> use String[] cmd = {"cmd","/c","type mytest.txt"} ,it dosn't work.

You don't need cmd.exe for this, other than that I have no idea.

(in fact you don't need Runtime.exec() for this at all).

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

Arne Vajhøj - 21 Oct 2006 00:04 GMT
>> how can i reading from stdio use this command:
>> type mytest.txt                    (win32)
>>
>> use String[] cmd = {"cmd","/c","type mytest.txt"} ,it dosn't work.
>
> You don't need cmd.exe for this, other than that I have no idea.

Since type is an internal command in cmd and not a type.exe, then
I would think cmd is needed.

Arne
Gordon Beaton - 21 Oct 2006 08:27 GMT
> Since type is an internal command in cmd and not a type.exe, then
> I would think cmd is needed.

I was assuming that type was a "real" program, but if that's not the
case then of course you're right.

/gordon (not a windows user)

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

Arne Vajhøj - 21 Oct 2006 00:04 GMT
> how can i reading from stdio use this command:
> type mytest.txt                    (win32)
>
> use String[] cmd = {"cmd","/c","type mytest.txt"} ,it dosn't work.

Try:

String[] cmd = {"cmd","/c", "type", "mytest.txt"};

Arne
crazzybugger - 21 Oct 2006 00:43 GMT
incase you get error paste your result here...........
crazzybugger - 21 Oct 2006 00:41 GMT
> I have an external program I need to execute which takes an argument.
> So I have the code:
[quoted text clipped - 34 lines]
> Thanks
> /Rune

I think you are doing a mistake here........If i am right you are
supposed to wait for the process to end .
     you can try out this sniplet.
try{
         Process p=Runtime.getRuntime().exec(yourCommand);
         int result=p.waitFor();
          if(result==0){

               /*this means that the program ran successfully.
                *now use your buffered stream and read from the
process using the
                 *process.getInputStream() call*/

           }else{

          /*program did not run successfully!
           *use your stream and read from the process using the

           * process.getErrorStream()*/

          }
}catch(Exception e){
            /*you reach here incase the process did not execute
properly or wrong arguements    */
}
Gordon Beaton - 21 Oct 2006 08:24 GMT
> I think you are doing a mistake here........If i am right you are
> supposed to wait for the process to end .

>  Process p=Runtime.getRuntime().exec(yourCommand);
>  int result=p.waitFor();
[quoted text clipped - 7 lines]
>     * process.getErrorStream()*/
>  }

This is a poor suggestion. You must read from both output and error
streams while the process is still running, or it will very likely
deadlock. Your method can only work for programs with very little
output (a few lines at most), and it certainly doesn't work for
programs that should run continuously.

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

crazzybugger - 21 Oct 2006 12:51 GMT
> > I think you are doing a mistake here........If i am right you are
> > supposed to wait for the process to end .
[quoted text clipped - 22 lines]
> [ don't email me support questions or followups ]
> g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

Yes my suggestion was for a code which will end quick enough . hence
there is no point of the suggestion being poor since it is well
understood from the sniplet that the code is expecting the process to
finish running quickly/or after a time interval.
          Incase you want the process to finish its execution within a
time limit , you could always spawn a thread which will count the  time
since the process's execution start and it can be used to kill it in
case it exceeds the time limit .(used by programming contests i
suppose) .
           So dont use it if your code is going to run continuously!
Gordon Beaton - 21 Oct 2006 15:18 GMT
> Yes my suggestion was for a code which will end quick enough . hence
> there is no point of the suggestion being poor since it is well
> understood from the sniplet that the code is expecting the process to
> finish running quickly/or after a time interval.

My comment had really nothing to do with the length of time a process
runs. It has everything to do with the amount of output it produces.

Any program that produces more than a few lines of output will *hang*
if you run it using your example. Yes it was necessary to point this
out since many posters to this group make that mistake anyway, even
without you telling them that this is a good way to use Runtime.exec()
(it isn't).

/gordon

Signature

[ don't email me support questions or followups ]
g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e

crazzybugger - 21 Oct 2006 15:45 GMT
> > Yes my suggestion was for a code which will end quick enough . hence
> > there is no point of the suggestion being poor since it is well
[quoted text clipped - 15 lines]
> [ don't email me support questions or followups ]
> g o r d o n  +  n e w s  @  b a l d e r 1 3 . s e
           you must have more experience to say so.........anyway i
have never tried out with programs giving larger output.........
probably it would.......but i wonder why ?
Chris Uppal - 22 Oct 2006 12:30 GMT
> > Any program that produces more than a few lines of output will *hang*
> > if you run it using your example. Yes it was necessary to point this
> > out since many posters to this group make that mistake anyway, even
> > without you telling them that this is a good way to use Runtime.exec()
> > (it isn't).
[...]
>             you must have more experience to say so.........anyway i
> have never tried out with programs giving larger output.........
> probably it would.......but i wonder why ?

No need for experience -- just a little knowledge will do ;-)

If the program attempts to write more to its stdout, or stderr, than the OS is
willing to buffer-up on its behalf (i.e. data that is sitting in the pipes
between that process and the parent Java process); then the OS will block the
writer until the reader has consumed some of the data.  Since the reader (Java)
is waiting for the writer to exit before it will read /anything/ from the pipe,
and since the writer is blocked waiting for the reader to read something before
it can exit, they both end up waiting for each other.

Deadlock.

Note that you have no control over how much data the OS will allow the writer
to put in the pipe before blocking it.  It is certainly OS-dependent, and might
be installation-dependent.

Don't ever use code like that in a production environment, and be very cautious
about using it even in throwaway code.

   -- chris
crazzybugger - 22 Oct 2006 16:11 GMT
> > > Any program that produces more than a few lines of output will *hang*
> > > if you run it using your example. Yes it was necessary to point this
[quoted text clipped - 26 lines]
>
>     -- chris

Excellent explanation!!!


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.