I am trying to run a command to read a string from a file inside a remote address (and I'm sure the file is there), this command works when I run it on the bash but it doesn't work when I run it in my java code.
Runtime rt = Runtime.getRuntime();
String[] command;
String line;
try {
command = new String[] {"sh", "-c", "\"sshpass " + "-p " + password + " ssh " + user + "#" + ip + " 'cat " + file.getAbsolutePath() + "'\"" };
Process mountProcess = rt.exec(command);
mountProcess.waitFor();
bufferedReader = new BufferedReader(new InputStreamReader(mountProcess.getInputStream()));
while ((line = bufferedReader.readLine()) != null) {
user_list.put(user, line);
}
bufferedReader.close();
bufferedReader = new BufferedReader(new InputStreamReader(mountProcess.getErrorStream()));
while ((line = bufferedReader.readLine()) != null) {
LOGGER.debug("Stderr: " + line);
}
bufferedReader.close();
} catch ...
No line is added to my user_list (so the line from getInputStream is null) and I get the following error from the logger in the code:
Stderr: sh: 1: sshpass: not found
If I use the exact same command on the bash it works and it prints the string I need.
sshpass -p password ssh remote#192.168.1.10 'cat /home/ID/ID'
Anyone knows why this is happening? thanks!
I'd suggest you don't need to use sh to wrap your command. Try
command = new String[] {"sshpass", "-p", password, "ssh", user + "#" + ip, "cat " + file.getAbsolutePath() };
If you need to use sh, then remove the escaped double quotes from the command string: you are sending those as literal characters:
command = new String[] {
"sh",
"-c",
String.format("sshpass -p %s ssh %s#%s 'cat %s'", password, user, ip, file.getAbsolutionPath())
};
If you're still getting "command not found", then you need to either specify the full path to sshpass, or ensure that its directory is in your PATH.
When doing this command with java the user is tomcat8 instead of root (when used in the bash terminal)
The solution that worked for me included some flags:
String.format("/usr/local/bin/sshpass -p %s /usr/bin/ssh -q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no %s#%s 'cat %s'", password, user, ip, file.getAbsolutePath());
Related
This is a part of my code to copy files from local to a remote machine
try {
Process cpyFileLocal = Runtime.getRuntime().exec("scp " + rFile+"*.csv" + " root#" + host + ":" + lFile);
InputStream stderr = cpyFileLocal.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
System.out.println("<ERROR>");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
System.out.println("</ERROR>");
int exitVal = cpyFileLocal.waitFor();
System.out.println("Process exitValue: " + exitVal);
System.out.println("...." + cpyFileLocal.exitValue());
System.out.println("SCP COMMAND "+"scp "+rFile+"*.csv" +" root#"+host+":"+lFile);
System.out.println("Sending complete...");
} catch (Exception ex) {
ex.printStackTrace();
}
the output is...
<ERROR>
/opt/jrms/rmsweb/transfer/cn00/outgoing/*.csv: No such file or directory
</ERROR>
Process exitValue: 1
....1
SCP COMMAND scp /opt/jrms/rmsweb/transfer/cn00/outgoing/*.csv root#10.50.1.29:/opt/jrms/transfer/incoming/
but when I run the command in terminal on the local machine, it works fine
and when I run ll the files are there
-rwxr-xr-x 1 freddie freddie 140 Apr 22 09:13 gc00cn00150420092629.csv*
-rwxr-xr-x 1 freddie freddie 105 Apr 22 09:13 gc00cn00150420122656.csv*
Any help please
If you are using java 7 and above you should use ProcessBuilder instead of Runtime.getRuntime().exec() and in the ProcessBuilder you can specipied the execution directory:
ProcessBuilder pb = new ProcessBuilder("scp", rFile+"*.csv", "root#" + host + ":" + lFile);
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory("directory where the csv files located");
Process p = pb.start();
When you run command with in bash with wildcards like * in it, bash will expand that command and in your case, replaces *.csv with list of files terminating with .csv, but in your java program, this won't happen.
According to this answer, you can do following:
Use file.listFiles() to get the list of files
Use file.getName().contains(string) to filter them if needed
Iterate over the array and perform scp or do it with whole list
or with thanks to #James Anderson comment add sh before scp in your command.
According to this, you should try:
Process cpyFileLocal = Runtime.getRuntime().exec(new String[] {"/bin/sh","-c", "scp " + rFile+"*.csv" + " root#" + host + ":" + lFile});
I tested with /bin/sh and /bin/bash, both copied the files over successfully
I am using this command line argument to clone a database :-
"C:\Program Files\MySQL\MySQL Server 5.6\bin\mysqldump" -u root -ppass -d oldDB | mysql -u root -ppass -DnewDB
This piece works fine when directly pasted into command line. But, when I tried running this argument using java, it did not work. My java code is :-
String serverLoc = "C:\\Program Files\\MySQL\\MySQL Server 5.6\\";
String a = "\"" + serverLoc + "bin\\mysqldump\" " ;
String cmd = a + "-u root -ppass -d oldDB | mysql -u root -ppass -DnewDB";
Process runtimeProcess = Runtime.getRuntime().exec(executeCmd);
int processComplete = runtimeProcess.waitFor();
if (processComplete == 0) {
System.out.println("SUCCESS");
} else {
System.out.println("ERROR");
}
//OUTPUT : ERROR
Exception handling not shown as no stack trace is printed. When I print cmd, the above desired string is printed which works when pasted into command line. Please help me solve this dilemma.
I believe on windows you have to call the command this way:
Runtime.getRuntime().exec("cmd " + ecuteCmd)
Also I think it is better to use Runtime.getRuntime().exec(String[]) method
String prog = "C:\\program files\\server\\xampp\\mysql\\bin\\mysql";
String user = "-uroot";
String pass = "-ppass";
Process runtimeProcess = Runtime.getRuntime().exec(new String[] { prog, user, pass });
The modern way by using ProcessBuilder: thx #Daniel
String prog = "C:\\program files\\server\\xampp\\mysql\\bin\\mysql";
String user = "-uroot";
String pass = "-ppass";
ProcessBuilder builder = new ProcessBuilder(prog, user, pass);
Process runtimeProcess = builder.start();
int result = runtimeProcess.waitFor();
//...
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};
I have java code which should stop windows service
When i try it on other commands which do not need admin permissions that works great but to stop windows service i have to start command line as administrator
I tried for example code to start notepad just for checking if this cooperation java with command line works great.
String[] start = {"cmd.exe", "/c", "start", "notepad"};
Process runtimeProcess = Runtime.getRuntime().exec(start);
int processComplete = runtimeProcess.waitFor();
but if i try command to run command line as administrator that failed:
String[] startAsAdmin= new String [] {
"CMD.EXE",
"/C",
"RUNAS /profile /user:"
+ "administrator"
+ " ", "start", "notepad"};
Process runtimeProcess = Runtime.getRuntime().exec(startAsAdmin);
runtimeProcess.waitFor();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(runtimeProcess.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(runtimeProcess.getErrorStream()));
BufferedWriter stdOutput = new BufferedWriter(new
OutputStreamWriter(runtimeProcess.getOutputStream()));
read the output from the command and put my original password to command line
when password is required (Zadejte heslo pro administrator means password required in english)
System.out.println("Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
if (s.startsWith("Zadejte heslo pro administrator:")) {
stdOutput.append("password").flush();
}
}
Why if i put my original password to command line like this it didn't works? It said Access Denied, but im sure that password is right and the next question is is there any possible way how can i do it without show my password in code?
Ohhh sry i now see ur update, but it still didn't start notepad:
String[] startAsAdmin= new String [] {
"CMD.EXE",
"/C",
"echo password123 | RUNAS /profile /user:"
+ "administrator"
+ " ", "start", "notepad"};
Process runtimeProcess = Runtime.getRuntime().exec(startAsAdmin);
int processComplete = runtimeProcess.waitFor();
You Should try this:
String[] stopAdmin= new String [] {
"CMD.EXE",
"/C",
"echo password123 | RUNAS /profile /user:"
+ "administrator"
+ " ", "net", "stop", Service_Name};
Process runtimeProcess = Runtime.getRuntime().exec(stopAdmin);
Hope this helps.
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.