I'm trying to use the "top" command from a standalone java app. I basically want to run this:
top -p myProcessId -n 1 -b
my java psuedocode:
Process process = Runtime.getRuntime().exec("top -p myProcessId -n 1 -b");
// read both:
process.getInputStream();
process.getErrorStream()
and the output I get is:
top: failed tty get
I'm not sure what that output means - any ideas how to use "top" correctly here? I'm on ubuntu fwiw.
Thanks
----- Update -------------
OK I was able to do this instead with:
ps -Ao pid,rsz,cmd
and then I read through each output line for the process I'm interested in, I can read the res mem value from there.
top doesn't use the ordinary standard output stream; it manipulates the terminal device directly. This means that you can't just read in its output like you can from most command-line programs. There are a few other programs that might do what you need (ps is a likely candidate), or you might be able to read the relevant information from /proc.
Related
I'm executing a command in order to write log messages into a file on the sdcard. This is already working:
String command = "logcat -f /storage/sdcard1/test.log";
Process logcatProcess = Runtime.getRuntime().exec(command);
Now I want to filter the log output by grep before writing it to the file like this:
String[] command = {
"/system/bin/sh",
"-c",
"logcat | grep -i Test01 >> /storage/sdcard1/test.log"
};
Process logcatProcess = Runtime.getRuntime().exec(command);
When I run the code from above the file is created but with no content. The grep command is surely installed on the system. What is wrong here?
logcat is outputting to grep live, but grep is processing data in big batches. Eventually, if there's enough output, grep should write something out.
(If you're writing to the terminal instead of to a file, grep is slightly less efficient and flushes after every line it sees, making it feel more interactive. This is not specific to Android's grep; you'll see this behavior on Linux or OS X also.)
If you use logcat -d, it'll terminate instead of polling for more logs, and grep will write out and terminate too. If that's not the behavior you want, you may end up needing to use ProcessBuilder to wrap logcat and re-implement grep (without buffering) inside your Java application.
I am wondering what the best course of action would be in order to get a java ".jar" file output into a python variable.
For example, let's say a user has a complicated java package (that perhaps the user didn't write and doesn't understand) which they can run in the command window / terminal with
java -jar FileProcessor.jar -i "input.txt" -o "output.txt"
Is there a manner to call this in python and get the "output.txt" in a variable, similar to this method:
proc = subprocess.Popen(['java', '-jar', 'FileProcessor.jar', '-i', 'sample.txt', '-o'], stdout=subprocess.PIPE)
py_out = proc.stdout.read()
print(py_out)
The problem is clearly that the java file looks for the output file "output.txt" after -o.
Obviously I am open to other ideas, but as I understand my main options are:
subprocess call/Popen? using stdout to log the variable
Write a wrapper of the java package
Is there a better way to achieve this? The first method doesn't appear to be working as easily as many examples would show and I have no idea how difficult it would be to write a wrapper around a java package as I have never done so.
if your program FileProcessor.jar doesn't have a special case to output to standard output, there's nothing much you can do (but write to a temporary file and read it again, but that's cheating :).
Most nice commands (Unix commands for instance) either dump data to stdout when the -o option is omitted, or when -o option has - value (dash).
if you cannot modify your program you can fool the program into believing it's writing on a file whereas it's writing on the console:
Linux/UNIX:
get current tty with tty command. Ex: /dev/pts/2
pass that to your program
read standard output
Windows:
use CON as output file name
read standard output
I'm trying to send a command to a minecraft server jar using /proc/{pid}/fd/0 but the server does not execute the command.
To replicate what I'm trying to do you can do this on a Debian based machine (possibly other Linux distributuions aswell).
What I use to test this:
Ubuntu 14.04
minecraft_server.jar (testing with 1.8)
OpenJDK Runtime Environment (installed with default-jre-headless)
First console:
$ java -jar minecraft_server.jar nogui
Response: [ ... server starts and waiting for input]
say hi
Response: [19:52:23] [Server thread/INFO]: [Server] hi
Second console:
Now when i switch to the second console, with the server still running in the first i write:
echo "say hi2" >> /proc/$(pidof java)/fd/0
Everything looks well until I switch back to the first console. I can see the text "say hi2" but the server hasn't recognized it. I can write another command in the first console again and it is as if the text inputted from the second console hasn't even existed.
Why is this? And more importantly, how do I use /proc/{pid}/fd/0 in a proper way to send commands to a java jar file?
I don't know if this is some kind of Java-thing that I'm not aware of, if I can use some flag or something when executing the server, or if it's the server jar itself that is the problem..
I'm aware that you can use screen, tail -f or some kind of server wrapper to accomplish this, but that's not what I'm after. I would like to send a command using this method, in some kind of way.
It's not a Java thing. What you are trying is simply not doable.
Test it like this:
Console1:
$ cat
This will basically echo anything you type on it as soon as you hit "return".
Console2: Find the process number of your cat command. Let's say it's NNN. Do:
$ echo Something > /proc/NNN/fd/0
Switch back to Console1. You'll see "Something" on the console output, but it's not echoed.
Why? Do
$ ls -l /proc/NNN/fd
And you may understand. All three descriptors, 0 for stdin, 1 for stdout and 2 for stderr are actually symbolic links, and all point to the same pseudoterminal slave (pts) device, which is the pts associated with your first terminal.
So basically, when you write to it, you actually write to the console output, not to its input. If you read from that file, you could steal some of the input that was supposed to go to the process in the first console (you are racing for this input). That's how a character device works.
The documentation for /proc says that:
/proc/[pid]/fd/
This is a subdirectory containing one entry for each file
which the process has open, named by its file descriptor, and
which is a symbolic link to the actual file. Thus, 0 is
standard input, 1 standard output, 2 standard error, and so
on.
So these are not the actual file descriptors opened by the process. They are just links to files (or in this case, character devices) with names that indicate which descriptor they are attached to in the given process. Their main duty is to tell you whether the process has redirected its file descriptors or has opened any new ones, and which resources they point to.
But if you want an alternative way of doing this, you can use a fifo - a named pipe.
Create a fifo by doing:
$ mkfifo myfifo
Run your java program:
$ java -jar minecraft_server.jar nogui < myfifo
Open another console. write
$ cat > myfifo
Now start typing things. Switch to the first console. You'll see your server executing your commands.
Mind your end-of-files, though. Several processes can write to the same fifo, but as soon as the last one closes it, your server will receive an EOF on its standard input.
It is possible to get around the fact that a named pipe is 'closed' when a process ends. You can to do this by keeping a file descriptor to the named pipe open in another process.
#! /bin/bash
# tac prints a file in reverse order (tac -> cat)
cmd="tac"
# create fifo called pipe
mkfifo pipe
# open pipe on the current process's file descriptor 3
exec 3<>pipe
bash -c "
# child process inherits all file descriptors. So cmd must be run from a sub-
# process. This allows us to close fd so cmd does not inherit fd 3, but allow fd 3
# to remain open on parent process.
exec 3>&-
# start your cmd and redirect the named pipe to its stdin
$cmd < pipe
" &
# write data to pipe
echo hello > pipe
echo world > pipe
# short wait before tidy up
sleep 0.1
# done writing data, so close fd 3 on parent (this) process
exec 3>&-
# tac now knows it will receive no more data so it prints its data and exits
# data is unbuffered, so all data is received immediately. Try `cat` instead to see.
# clean up pipe
rm pipe
This is an extremely strange situation, but I just cannot point out what I'm doing wrong.
I'm executing a big bunch of SQL scripts (table creation scripts, mostly). They are executed through Java, using sqlcmd. Here's the sqlcmd command I use.
sqlcmd -m 11 -S SERVER -d DB -U USER -P PASS -r0 -i "SCRIPT.sql" 2> "ERRORS.log" 1> NULL
Note: I use the -r0 and redirects to make sure only errors go into the log file. I chuck out all STDOUTs.
Now I execute this command in Java, using getRuntime.exec(), like this.
Runtime.getRuntime().gc();
strCmd = "cmd /c sqlcmd -m 11 -S SERVER -d DB -U USER -P PASS -r0 -i \"SCRIPT.sql\" 2> \"ERRORS.log\" 1> NULL"
Process proc = Runtime.getRuntime().exec(strCmd);
proc.waitFor();
Note: I use cmd /c, so that the command runs in its own shell and exits gracefully. Also, this helps in immediately reading the error log to look for errors.
The Problem!
This command works perfectly when run by hand on the command prompt (i.e. the tables are getting created as intended). However, when executed through Java as shown, the scripts are run, and and there are no errors, no exceptions, nothing in the logs. But, when checking in SSMS, the tables aren't there!
Where do I even begin debugging this issue?
UPDATE: I'M A MORON
The return value from the getRuntime().exec method is 1. It should be 0, which denotes normal execution.
Any pointers on how to fix this?
UPDATE 2
I've looked at the process' ErrorStream, and this is what it has.
Sqlcmd: Error: Error occurred while opening or operating on file 2>
(Reason: The filename, directory name, or volume label syntax is
incorrect).
Looks like the path I'm passing is wrong. The error log goes into my profile directory, which is C:\Documents and Settings\my_username. Do the spaces in the path matter? I'm anyways double-quoting them!
Have a look at the exec method with an string array as parameter:
java.lang.Runtime.exec(String[] cmdArray)
The JavaDoc for this method says:
Executes the specified command and arguments in a separate process.
So, the first item in the array is the command and all of your arguments are appended to the array, e. g.,
Runtime.getRuntime().exec(new String[] {"cmd", "/c", "sqlcmd ... "});
After looking at your comment and the implementation of exec(String) it seems to be, that the exec method recognizes the pipe operator > as an argument to cmd, because exec(String) splits the command string to an array using whitespaces as seperators.
I don't have privs to post comments - which is what this is - but what if you try putting in a bogus user id for the DB? Does that cause a different execution path? Will that give you a Java error? Or an Auth error in your DB? Also, def tweak the user, not the password and learn from my experience that if you tweak the password that's a great way to get an account locked out!
The other thing - and this may be a shot in the dark - but what are the JRE and driver you're using? I believe there's a known issue with JRE 1.6.0.29 and the sqljdbc4 JAR. I have more details on this, but I'll have to post the link once I get to work.
Edit:
I know it's been established that the JRE/sqljdbc combo isn't your issue, but if folks search and find this, here is the link I spoke of above:
Driver.getConnection hangs using SQLServer driver and Java 1.6.0_29
First enable log/view commands output (since exec() returns 1), which would point out possible cause of the issue.
Use proc.getInputStream() and print the contents to a file or console.
I need some help writing a command that will be put into a .sh. I want to return the process id, which in the output below is 3678, but I'm having diffuclty because the process id changes everytime it gets restarted, so my code breaks
Output:
[root#server1 /usr/home/aaron]# ps -xauww | grep java | grep www
www 3678 0.0 3.2 1308176 267864 ?? Is 3:21PM 0:17.19 [java]
[root#server1 /usr/home/aaron]#
Heres what I was doing until I realized the column changed when the pid changed:
ps -xauww | grep java | grep www | cut -d" " -f6
Any help is appreciated. thanks.
If the starting is automated by a shell script, you can write the pid of the just-started-process which is in the variable $!.
java ...... &
echo "$!" > myjavaprogram.pid
When you need to kill it, just do:
kill `cat myjavaprogram.pid`
Below pgrep command works for getting pid by jar-file name:
pgrep -f test-app.jar
As per http://cfajohnson.com/shell/cus-faq-2.html
How do I get a process id given a process name? Or, how do I find
out if a process is still running, given a process ID?
There isn't a reliable way to to this portably in the shell. Some
systems reuse process ids much like file descriptors. That is,
they use the lowest numbered pid which is not currently in use
when starting a new process. That means that the pid you're
looking for is there, but might not refer to the process you think
it does.
The usual approach is to parse the output of ps, but that involves
a race condition, since the pid you find that way may not refer to
the same process when you actually do something with that
pid. There's no good way around that in a shell script though, so
be advised that you might be stepping into a trap.
One suggestion is to use pgrep if on Solaris, and 'ps h -o pid -C
$STRING' if not, and your ps supports that syntax, but neither of
those are perfect or ubiquitous.
The normal solution when writing C programs is to create a pid
file, and then lock it with fcntl(2). Then, if another program
wants to know if that program is really running, it can attempt to
gain a lock on the file. If the lock attempt fails, then it knows
the file is still running.
We don't have options in the shell like that, unless we can supply
a C program which can try the lock for the script. Even so, the
race condition described above still exists.
That being said look at this: http://www.faqs.org/faqs/unix-faq/faq/part3/section-10.html it might help you out ?
One way can be found in: man pgrep