Problem while executing "tar -ztf" command in Java - java

I am trying to run "tar -ztf /users/home/test.tar.gz | head -1" in Java, which worked when I tried to run it in unix command line directly.
The result of this command will list one line of the file/folder inside of the test.tar.gz.
for example: proj/test/test_dir
But I when I run it in java. it will give this error:
Running command: tar -ztf /users/home/test.tar.gz | head -1
[java] tar: Options `-[0-7][lmh]' not supported by *this* tar
[java] Try `tar --help' for more information.
Any idea what's wrong with it? why is it related to "specify drive and density" option?
The code I have run:
String s = null;
StringBuffer sbOutput = new StringBuffer();
StringBuffer errorInfo = new StringBuffer();
String[] cmd = {"tar", "-ztf", fileName, "|", "head", "-1"};
try
{
Runtime rt = Runtime.getRuntime();
System.out.println("Running command: " + cmd[0] + " " + cmd[1] + " " + cmd[2] + " " + cmd[3] + " " + cmd[4] + " " + cmd[5]);
Process p = rt.exec(cmd);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
//If there is an error - only show that
while ((s = stdError.readLine()) != null)
{
errorInfo.append(s + "\n");
}
if (errorInfo.length() > 0)
{
System.out.println(errorInfo.toString());
}
while ((s = stdInput.readLine()) != null) {
sbOutput.append(s + "\n");
}
// wait for end of command execution
try {
p.waitFor();
} catch (InterruptedException ie) {
new LogErrThread(ie).start();
ie.printStackTrace();
}
p.destroy();
if (sbOutput.length() > 0)
{
System.out.println(sbOutput.toString());
}
}
catch (IOException e)
{
new LogErrThread(e).start();
e.printStackTrace();
}

On the command line, the shell is doing the piping for you. Only the arguments before the | are passed to gtar. Your code incorrectly passes the pipe and the rest of the text as arguments to gtar.
Luckily, the solution is simple. You can simply read the first line yourself.
String[] cmd = {"gtar", "-ztf", fileName};
// ...
// Instead of current input loop.
s = stdInput.readLine();
if(s != null) {
sbOutput.append(s + "\n");
}
while (stdInput.readLine() != null) {
// Disregard. Reading to end to prevent hang.
}

To elaborate Matthew's point, the | operator is interpreted by the shell. To run your command without the shell, you would need to launch the programs separately and connect their pipes together (tricky in Java).
If you input is sanitized, you can invoke the shell and give it the command to run. Its the easier approach, though arguably less portable. In general, the SHELL environment variable contains the user's shell. Shells also have a defacto standardized -c option to pass them a command string in argv. If you invoke $SHELL -c [command string], you should get the behavior you want.

Related

Java system command to load sqlite3 db from file fails

I'm trying to use java to run a system command to load a sqlite3 database from a sql file. There is no error in the sql file, it loads ok using the usual method from the command line:
sqlite3 dbname < file.sql
My method:
public void loadSqlFile(String file, boolean tearDown) {
String s = null;
try {
Process p = Runtime.getRuntime().exec(
"/usr/bin/sqlite3 " +
database +
" < " +
file
);
p.waitFor();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
} catch (IOException e) {
LOGGER.error("Failed to load sql file (" + file + ")");
} catch (InterruptedException e) {
LOGGER.error("Failed to load sql file (" + file + ")");
}
}
The command being run translates to:
/usr/bin/sqlite3 /tmp/infinite_state_machine_root/1535223603610/control/database/ism.db < /tmp/ISMCoreActionPack_sqlite3.sql
And the error I see on stdout is:
Error: near "<": syntax error
I've searched for a lot of examples of running system commands and can't find anything that explains this error, at least to me!
I have tried other commands in there like ps and so on and they seem to run ok.
Any advice?
I'm running this on a MAC if that is significant.
Hi you would need to use ProcessBuilder to run redirect on input. Should be something around these lines.
ProcessBuilder builder = new ProcessBuilder("sqlite3", database);
builder.redirectInput(file);
Process p = builder.start();

Java program not getting output from terminal

I am running my Java program from terminal and I am trying to count the number of files in a certain directory using a linux command in my code; I have managed to get output for all other commands but this one.
My command is: ls somePath/*.xml | wc -l
When I run my command in my code, it appears that it has nothing to output, yet when I run the same exact command in terminal it works just fine and actually outputs the number of xml files in that directory.
Here is my code:
private String executeTerminalCommand(String command) {
String s, lastOutput = "";
Process p;
try {
p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
System.out.println("Executing command: " + command);
while ((s = br.readLine()) != null){//it appears that it never enters this loop since I never see anything outputted
System.out.println(s);
lastOutput = s;
}
p.waitFor();
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
return lastOutput;//returns empty string ""
}
Updated code w/ output
private String executeTerminalCommand(String command) {
String s, lastOutput = "";
try {
Process p = new ProcessBuilder().command("/bin/bash", "-c", command).inheritIO().start();
//Process p = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
System.out.println("Executing command: " + command);
while ((s = br.readLine()) != null){
System.out.println("OUTPUT: " + s);
lastOutput = s;
}
System.out.println("Done with command------------------------");
p.waitFor();
p.destroy();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("LAST OUTPUT IS: " + lastOutput);
return lastOutput;
}
output:
Executing command: find my/path -empty -type f | wc -l
Done with command------------------------
1
LAST OUTPUT IS:
To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.
Process p = new ProcessBuilder().command("bash", "-c", command).start();
bash invokes a shell to execute your command and -c means commands are read from string. So, you don't have to send the command as an array in ProcessBuilder.
But if you want to use Runtime then
String[] cmd = {"bash" , "-c" , command};
Process p = Runtime.getRuntime().exec(cmd);
Note: You can check advantages of ProcessBuilder here and features here over Runtime

Executing Linux Commands in java

I need to copy files of specific pattern from one director to another
File Pattern: "nm.cdr.*(asterisk)-2014-08-16-14*(asterisk).gz"
Command: "cp " + inputPath + filesPattern + " " + destPath;
If i use specific file instead of using * than it works fine(for single file) but with pattern using * it doesn't work.
Edit 1: I tried following code:
public void runtimeExec(String cmd)
{
StringBuffer output = new StringBuffer();
Process p;
try
{
p = Runtime.getRuntime().exec(cmd);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
}
catch (IOException | InterruptedException e)
{
LogProperties.log.error(e);
}
}
The asterisk is something interpreted by the shell, so you need to use the shell as the main process, the command line for the process in Java would be something like bash -c '/origin/path/nm.cdr.*-2014-08-16-14*.gz /destination/path'.
Now, if you try to use this command in a single string it won't work, you need to use a String[] instead of a String. So you need to do the following:
1: change your method's signature to use a String[]:
public void runtimeExec(String[] cmd)
2: call your method with this value for cmd:
String[] cmd = new String[] {"bash", "-c",
"cp " + imputPath + filesPattern + " " + destPath};
Can't see what exactly is passed as a command, but on linux often is necessary to split command and parameters to string array, like:
String[] cmd = {"cp", inputPath+filesPattern, destPath};

running grep command in command line and from java code gives different results

When I run the below grep command in terminal, I get the list of line numbers. But when i tried doing the same via java code i didn't any result. I am not sure what went wrong here.
Thank in advance
grep -in "callback recieved" /home/local/ws/ui_auto/UIAutomator/result/test/logs | cut -f1 -d:
public List<Integer> getLineNumbers(String pattern, String file, String pat) {
String[] cmd = { "/bin/sh", "-c", "grep -in \""+ pattern + "\" " + file + " | cut -f1 -d:"}; // > " + file + "_" + pat };
System.out.println(cmd[2]);
Process proc;
List<Integer> rline = new ArrayList<Integer>();
try {
proc = Runtime.getRuntime().exec(cmd);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
rline.add(Integer.parseInt(line));
}
} catch (IOException e) {
System.out.println(e);
}
return rline;
}
As per as our discussion in comments.If putting a sleeep of 1 second has worked for you. Try putting :
proc.waitFor();
Process.waitFor() blocks the current thread until the process has
terminated, at which point the execution control returns to the thread
that spawned the process.
Put it after: proc = Runtime.getRuntime().exec(cmd);

shell Command execution Failing when executed from Java

When I execute the below command on command line, it shows all the stored procedures and tables in the sybase DB.
printf 'sp_help\ngo\n' | isql -Uxx -Pxxxx -Dxxxxx
But when I do the same thing in java. This does not return any result.
Can anyone tell me what is the problem with my code below:
public class test
{
public static void main(String[] args)
{
String cmd = "printf "+"\'sp_help\ngo\n\'"+"| isql -Uxx -Pxxxx -Dxxxxx" ;
try{
Process p;
p = Runtime.getRuntime().exec(cmd);
p.waitFor();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = reader.readLine())!=null){
System.out.println("Row is :" + line);
} catch(Exception e)
{
System.out.println("Exception Caught : " + e);
}
}
}
EDIT
I executed it as below suggested by Darkdust but still it doesnt work.
try{
Process p;
p = Runtime.getRuntime().exec("sh -c \'printf \"sp_help\ngo\n\" | isql -Uxx -Pxxxxx -Dxxxxxx\'");
p.waitFor();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = reader.readLine())!=null){
System.out.println("Row is :" + line);
}
}
catch(Exception e)
{
System.out.println("Exception Caught : " + e);
}
But the command :
sh -c 'printf "sp_help\ngo\n" | isql -Usa -Psybase11 -Dcnadb'
Works on command line.
I also tried with :
p = Runtime.getRuntime().exec(new String[]{"sh","-c","\'printf \"sp_help\ngo\n\"","|isql -Uxx -Pxxxxx -Dxxxxx\'"});
But with no sucess.
Several things come to mind:
Incomplete PATH environment variable (thus isql can't be found).
If it's a command you provide, instead of messing with PATH you might want to make sure your are you in the correct working directory and call ./isql instead.
Since you're using a pipe, you should let a shell execute this as in sh -c "foo | bar". Otherwise the | isql ... part is passed as argument to printf as well.

Categories

Resources