I'am currently changing our system to use another server for getting file (files generated for tracking something, not important). This system is based on java, and the code for getting these files are using Linux commandos. The code for getting these files are:
session = connection.openSession();
session.execCommand("ls -B -A " + filelocation);
output = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStdout()), "UTF-8"));
This did however work on our original server (x86_64 GNU/Linux), but does not work on the "new" server (SunOs 5.10 Generic January). When running this command on the SunOS server i get:
ls: illegal option -- B
usage: ls -1RaAdCxmnlhogrtuvVcpFbqisfHLeE# [files]
I am far from well versed with with the commandline, and I have not written the original code. But this is what i figured
-A, --almost-all Do not list implied . and ..
-B, --ignore-backups Do not list implied entries ending with ~
Is there an optional way of getting this to work on the SunOS server?
EDIT
Checking each String read if line.endsWith("~");
while ((outputString = output.readLine()) != null) {
if(!outputString.endsWith("~")){
fileList.add(outputString);
}
}
Either you can write a shell script new_ls calling ls and removing the lines that end with "~"
Or when you process the results in java you can also ignore lines read from the BufferedReader by checking each String read if line.endsWith("~");
Related
Working condition :
Process process = Runtime.getRuntime().exec("ls -l /etc/");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
Log.d(TAG,"bufferedReader.readLine()===>"+bufferedReader.readLine());
Snipped log : bufferedReader.readLine()===>total 7580
not working :
Process process = Runtime.getRuntime().exec("./etc/lighttpd -D -f /etc/test.conf");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
Log.d(TAG,"bufferedReader.readLine()===>"+bufferedReader.readLine());
Snipped log : bufferedReader.readLine()===>null
Can you please help me, why I am receiving bufferedReader.readLine() is "null" while execute "./etc/lighttpd -D -f /etc/test.conf" command
executed below command in device shell :
#./etc/lighttpd -D -f /etc/test.conf
2022-08-30 12:38:18: server.c.1508) server started (lighttpd/1.4.58)
The pathname ./etc/lighttpd is suspicious, but the evidence you have show us proves that:
it is present, and
it is executable,
... at least for some current directory.
Why do I say that it is proven? Because:
exec didn't throw an IOException, and
you showed us the output from running the same command from the command line.
Admittedly, it is possible that the current directories are different ... which is one of the reasons that I said that ./etc/lighttpd is suspicious!
So if the problem is not that ./etc/lighttpd is not an executable, what is the explanation for bufferedReader.readLine() returning null?
Well, the simplest theory is that lighttpd is writing to standard error rather than standard output, and that it has closed its standard output. That would explain the behavior you are seeing.
Anyhow ... my suggestions would be:
Change ./etc/lighttpd to the absolute pathname for the executable that you are using ... to remove any doubt.
Try opening and reading from process.getErrorStream() instead.
Look in the lighttpd log file for any errors.
Finally, you have tagged your question with [android] but AFAIK there is no (official) Android port for Lighttpd. I am guessing that the tag was a mistake because there is no other mention of Android. But if it was not a mistake, you should tell us where you go the Android port from. That may help people to diagnose the problem.
/etc/lighttpd is usually a directory containing configuration information. /etc/lighttpd is often not an executable.
I'm calling pscp from Java using the following code:
public static ArrayList<String> runWindowsCommand(String... args) throws WindowsCmdFault {
try {
ProcessBuilder pb = new ProcessBuilder(args);
Process p = pb.start();
//...
//... code to fetch the output and return it back
}catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
I call this function as follows:
runWindowsCommand("C:\Program Files (x86)\PuTTY\pscp" -pw "password" -r folder/file_to_be_transferred.txt "username#hostname:/remote/unix/server/location/folder_name")
This executes fine and shows the following output:
Arraylist returned (output) =
[, file_to_be_transferred.txt | 3 kB | 2.7 kB/s | ETA: 00:00:00 | 100%]
It appears that the transfer was successful. Except that when I login to the remote unix server via putty and check that file, it shows that nothing was updated.
The file's permission has been set to 666.
When I execute this same command (that we're sending to the function) directly on the cmd prompt, then it gives the same output and the file is actually transferred.
When I run this same command via the Java code given above the file isn't actually transferred.
Why is PSCP not transferring the file?
Update:On further investigation and a big thanks to #Martin Prikryl, I was able to narrow down this issue to the root cause.
Root cause:
The problem is that when the user connection is established from the PSCP, then it connects by default to
(root)/home/username .
The directory that we need to traverse to lies in
(root)/www/....lengthy/folder/here .
Remaining problem:
I'm trying to traverse upwards through the folders after connecting. I'm trying to add a double-period in order traverse upwards towards the root before supplying my path. But it doesn't work.
I'm trying this with pscp as the remote hostname:
../../www/..lengthy/folder/here
but this fails for some odd reason when executed through Java but works through cmd prompt.
How can I add a remote path that includes the second parent before including my actual path?
It seems like there's some limitation when you use Java + PSCP. I solved this problem by uploading the file to a default directory. After that I make a connection via putty's command-line and transfer the file to the required destination. I'm placing my answer over here.
I am trying to write a unix terminal emulator in java. I am having a lot of trouble. It doesn't seem like I can change the working directory of the program, so commands like "cd" aren't working properly. My question is this, If I run a command that requires input from the user, is there any way to send that input to the running process?
Thanks so much, that was a lot of help. Here's an example:
InputStream in = null;
OutputStream outS = null;
StringBuffer commandResult = new StringBuffer();
String line = null;
int readInt;
p = Runtime.getRuntime().exec("gksudo apt-get install firefox");
int returnVal = p.waitFor();
in = p.getInputStream();
while ((readInt = in.read()) != -1)
commandResult.append((char)readInt);
outS = (BufferedOutputStream) p.getOutputStream();
outS.write("Y".getBytes());
outS.close();
System.out.println(commandResult.toString());
in.close();
This is the output:
Reading package lists...
Building dependency tree...
Reading state information...
The following packages were automatically installed and are no longer required:
libmono2.0-cil libmono-data-tds2.0-cil libmono-system-data2.0-cil
libdbus-glib1.0-cil librsvg2-2.18-cil libvncserver0 libsqlite0
libmono-messaging2.0-cil libmono-system-messaging2.0-cil
libmono-system-data-linq2.0-cil libmono-sqlite2.0-cil
libmono-system-web2.0-cil libwnck2.20-cil libgnome-keyring1.0-cil
libdbus1.0-cil libmono-wcf3.0-cil libgdiplus libgnomedesktop2.20-cil
Use 'apt-get autoremove' to remove them.
The following extra packages will be installed:
firefox-globalmenu
Suggested packages:
firefox-gnome-support firefox-kde-support latex-xft-fonts
The following NEW packages will be installed:
firefox firefox-globalmenu
0 upgraded, 2 newly installed, 0 to remove and 5 not upgraded.
Need to get 15.2 MB of archives.
After this operation, 30.6 MB of additional disk space will be used.
Do you want to continue [Y/n]? Abort.
Why is it aborting before I can pipe in the "Y"?
Yes; see Process#getOutputStream() to get the "standard input" (stdin) stream for a Process object.
As for the issue of changing directory, I don't believe the JVM can change its working directory once it has launched. However, your program could model the idea of the "current working directory" as a variable which it uses when it does things which are relative to that location (e.g. launching processes, listing directory contents, etc). The ProcessBuilder class even has a way to set the working directory for Processes it produces.
I need to execute a command from a program. The command line is ok, I tried it in the terminal, but it doesn't work in the program.
I add a copy from my code:
File dir = new File("videos");
String[] children = dir.list();
if (children == null) {
// Either dir does not exist or is not a directory
System.out.print("No existe el directorio\n");
} else {
for (int i=0; i<children.length; i++) {
// Get filename of file or directory
String filename = children[i];
//Recojo el momento exacto
System.out.print("\n" +filename);
Process p = Runtime.getRuntime().exec("exiftool -a -u -g1 -j videos/"+filename+">metadata/"+filename+".json");
}
The program must get the name of all of the files in a folder (filename) and extract the metadata of theese videos, writting them on a .json files in the folder 'metadata'.
Where is the problem?
The problem is, the redirection character (>) is a shell-based construct, not an executable. So unless you're running this command through something like bash (which you're not), it's going to be interpreted as a literal character argument to your exiftool invocation.
If you want to get this to work, you have two options:
Get bash to do it - pass the whole command line as an argument to bash -c. This might need some heroic escaping, although in your case it looks OK.
Do the redirection yourself within Java. Invoke the command without the redirected output (i.e. everything up to the > sign), then read from the process' outputstream and write all the contents to the appropriate file.
The latter approach sounds like more work initially, but when you consider that you need to always read a Process' output anyway (see the javadocs, second paragraph), it's actually very little extra on top of that. You're simply sending this output to a file instead of throwing it away.
If you have Java 7, it's easier:
Process p = new ProcessBuilder()
.command("exiftool", "-a", "-u", "-g1", "-j",
new File("videos", filename).toString())
.redirectOutput(new File("metadata", filename + ".json"))
.start();
This falls under "solution 2", but the runtime library takes care of the boilerplate.
I'm currently working on a web application that involves mounting a drive and extracting a tar.gz file, all in Java. Since the application runs in a linux environment, I figured I'd try using unix commands like "mount" and "tar".
Runtime runtime = Runtime.getRuntime();
Process proc;
String mountCommand = "mount -t cifs -o username=...";
String extractCommand = "tar xzf ..."
proc = runtime.exec(mountCommand);
proc.waitFor();
proc = runtime.exec(extractCommand);
proc.waitFor();
Running the mount command and extract command in the terminal works fine, but fails when FIRST run in java. The second proc.waitFor() returns exit code 2. However, running this code after the first failed attempt works fine. I have a feeling that the problem is that waitFor() isn't waiting until the mount command is fully completed. Am I missing anything important in my code?
Also, I'd rather do this all in Java, but I had a really hard time figuring out how to untar a file, so I'm taking this approach. (oh if anyone can tell me how to do this i would be very happy). Any suggestions would be muuuuuuuuuuch appreciated!
Making progress. In case anyone was wondering, here is how I am extracting a tar.gz file in Java. Put together from a few online tutorials.
public static void extract(String tgzFile, String outputDirectory)
throws Exception {
// Create the Tar input stream.
FileInputStream fin = new FileInputStream(tgzFile);
GZIPInputStream gin = new GZIPInputStream(fin);
TarInputStream tin = new TarInputStream(gin);
// Create the destination directory.
File outputDir = new File(outputDirectory);
outputDir.mkdir();
// Extract files.
TarEntry tarEntry = tin.getNextEntry();
while (tarEntry != null) {
File destPath = new File(outputDirectory + File.separator + tarEntry.getName());
if (tarEntry.isDirectory()) {
destPath.mkdirs();
} else {
// If the parent directory of a file doesn't exist, create it.
if (!destPath.getParentFile().exists())
destPath.getParentFile().mkdirs();
FileOutputStream fout = new FileOutputStream(destPath);
tin.copyEntryContents(fout);
fout.close();
// Presserve the last modified date of the tar'd files.
destPath.setLastModified(tarEntry.getModTime().getTime());
}
tarEntry = tin.getNextEntry();
}
tin.close();
}
Quick Answer
Since a dependency on external commands exists, simplify it like this:
#!/bin/bash
mount -t cifs -o username=...
tar xzf ...
Name it mount-extract.sh then call it using a single Runtime.exec() call.
Semi-integrated Answer
Use Java APIs.
http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/GZIPInputStream.html
http://www.jajakarta.org/ant/ant-1.6.1/docs/ja/manual/api/org/apache/tools/tar/TarInputStream.html
You will need Runtime.exec to execute the mount command.
Forward Looking
Since Java is a cross-platform software development tool, consider abstracting the mount command in your application to be derived dynamically based on the underlying operating system.
See: How can I mount a windows drive in Java?
See: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#getProperties()
Of course, Agile development would insist that this not be done until it is needed. So keep it in the back of your mind until then (as you might never run the application on anything but Unix-based systems).
Take a look at the org.apache.tools.tar package in the Ant codebase. There is a class in that package, TarInputStream, that can be used to read tar archives.
It may be related to the way you call the method.
See this answer
Basically try using
.exec( String [] command );
instead of
.exec( String command );
I'm not sure if it is even related, because you mention it runs the second time. Give it a try and let us know.
This can all be done in Java, but you have to be aware of caveats when dealing with native processes.
The waitFor() command may not be doing what you hope: if the process you started has a child process that does the actual work you need then the waitFor(), which returns when the parent process has finished, has not allowed enough time for the child process to finish.
One way to get around this is to loop over some test to see that the native processes you started have finished to your satisfaction---in this case perhaps checking if some java.io.File exists.