So I'm using the coproc command in a script to run a java program and to feed input to it, as follows:
#!/bin/bash
echo Script started.
coproc java -jar MultiThreadedFileProcessor.jar
echo start >&${COPROC[1]}
echo Script terminated.
I'd like to be able to write another script which can pass more input to this program (e.g. a command which will tell the program to run termination routines).
Is there any way that I can access the stdin of the coprocess from another script? My current attempt at a termination script is as follows:
#!/bin/bash
echo Script started.
echo terminate >&${COPROC[1]}
echo close >&${COPROC[1]}
echo Script terminated.
This gives me an ambiguous redirect error however, I'm guessing because COPROC[1] is only defined in the script that creates the coproc.
How else, if at all, can I write a script that will accomplish my goal of passing a line to the java program?
COPROC is an array local to the first script - you will never be able to access that from another script.
On Linux, you could access /proc/$pid/fd/$n with $pid being the pid of the first script and $n being the fd stored in ${COPROC[1]}. Both have to be communicated somewhere (a pid file and likewise an "fd file"), but in that case you might better be off creating a named pipe (mkfifo) and use that instead of creating a coproc in the first place. Something like this (not tested) codes:
Script 1:
mkfifo fifoname
exec 5>fifoname
java <fifoname &
echo close >&5
Script 2:
exec 5>fifoname
echo terminate >&5
echo close >&5
What is the close command supposed to do? The java program will see
close
terminate
close
Does that make sense to the java program?
Related
I have inherited an extract job program which is a Java program that connects to a database and produces a file from a Unix shell script. At times, I can see the Java program is terminated abnormally and starts executing the remainder of the Unix script by zipping the extract. This is causing a lot of reconciliation issues.
The code is structured as follows:
INSTANCE_NAME=1
PROCESS_NAME=benefitpayment
cd utils
FAIL=0
sh benefitpaymentprocesswithdates.sh $PROCESS_NAME $INSTANCE_NUMBER $1 $2
for job in $dPidLst
do
wait $job || let "FAIL+=1"
done
echo $FAIL
if [ "$FAIL" == "0" ];
then
echo "About to secure file..."
zip -P <password> export.txt secure.zip
...
...
else
echo "FAIL! ($FAIL)"
fi
The $dPidLst is set in the inner Unix script(benefitpaymentprocesswithdates.sh) to call a Java wrapper and is set as:
java program called to generate a file
dPidLst=`jobs -p`
In either of the successful or failure cases, this "dPidLst" is always NULL.
The dPidLst is not exported in the inner script. The script was designed in that manner.
Should dPidLst be exported back to this main program? How do I make this script fool proof in the sense, if the Java program terminates abnormally, it should not execute the remainder of the Shell script? of zipping the file.
The value of dPidLst that you set in benefitpaymentprocesswithdates.sh will not be visible in your calling script.
When you run the benefitpaymentprocesswithdates script, it runs in its own process, and that process gets its own variables.
To pass the process id list back to your script, you need to use a mechanism other than shell variables or environment variables
e.g. at the end of benefitpaymentprocesswithdates.sh, do
echo $dPidList
And when you call it instead of
sh benefitpaymentprocesswithdates.sh
do
dPidList=$(sh benefitpaymentprocesswithdates.sh)
If all it is doing is calling jobs -p, there's no reason to have it in a separate script, of course.
I am starting a Java code from Bash script called start.sh. The Bash script fires up the Java code and then the Java code runs. At the end of the Java program, I want to send a signal back to the Bash script to terminate. Keep in mind that the Bash script runs with PID = 1. And I have to kill the PID 1 process.
I have the bash script set up such that it runs in an infinite loop and waits for a termination signal:
#!/bin/bash
# Run the java code here..
# Listen for an exit command.
trap 'exit 0' SIGTERM
while true; do :; done
I am using Docker instances and the signal is sigterm. I am following this tutorial: https://www.ctl.io/developers/blog/post/gracefully-stopping-docker-containers/ which explains how to send a sigterm from command line. I want to automate this process and close/kill the docker instance from inside as soon as the Java program ends.
How do I send the signal back to the bash script that started the Java code in the first place?
Should I follow
this method to send a signal as arguments to the bash script? Or will it start another bash script with a different PID (not 1).
Help needed!
Write 'set -e' in second line in bash script.
Dont use trap and while. Replace it by
'exec your_java_code_run'.
By this way docker get SIGTERM after java code run end.
Exemple:
#!/usr/bin/env bash
set -e
someOtherCodeIfNeed
exec your_java_code_run
I am running a minecraft server for my son, i'm new at minecraft servers, anyway it seems it keeps dying as it cant keep up? ok so its a VM and i will be assigning more resources to it at some point but my question is as follows
I initiate the server to load up via a script
bukkit.sh is the script an inside it has
#!/bin/bash
java -Xmx1024M -jar /minecraftserver/bukkitserver/craftbukkit-1.7.1.jar -o true
now at somepoint during the day or night it will die as it cant keep up, is there a way i can have some other script run alongside it and see that the process has died and to run that script again to start the server.
when i run top i can see that java is at the top using all the resources so im 100% thats the minecraft java. Does the PID stay the same each time it loads up?
Would be great if someone could let a hand on this ...
I assume the java process remains in the foreground once it's launched? Is there any reason you can't just do:
while :
do
java -Xmx1024M -jar /minecraftserver/bukkitserver/craftbukkit-1.7.1.jar -o true
done
Then any time the java exits, the script will simply restart it.
EDIT:
You could create a script, lets call it craftbukkit.sh
Make sure it is execute by using: chmod +x craftbukkit.sh
Then inside the script you would write:
#!/bin/sh
ps auxw | grep craftbukkit-1.7.1.jar| grep -v grep > /dev/null
if [ $? != 0 ]
then
/path/to/your/bukkit.sh
fi
Change /path/to/your/bukkit.sh to wherever that minecraft startup script is.
Then you need to add this script to your crontab, this is accomplished by entering the crontab editor: crontab -e
If you want the script to run every 5 minutes, add a line that looks like this:
*/5 * * * * /path/to/craftbukkit.sh
Note that you must change the /path/to to point to where you have created the craftbukkit.sh script.
I'm trying to restart process when OOME happens. Java binary is launched using two shell scripts, one of them imports other. I don't have any control of the first one but can modify the second one as I want.
This is a prototype what I'm trying to do:
First shell script test.sh:
#!/bin/sh
JAVA_OPTS="$JAVA_OPTS -Xmx10m"
. test1.sh
echo $JAVA_OPTS
java $JAVA_OPTS $es_params TestMemory
Second shell script test1.sh:
#!/bin/sh
pidfile="test.pid"
touch $pidfile
params="$parms -Dpidfile=$pidfile"
kill_command="kill -9 \$(cat $pidfile)"
dir=$( cd $(dirname $0) ; pwd -P )
path="$dir/$(basename $0)"
start_command="$path $#"
restart_command="$kill_command;sleep 2;$start_command"
JAVA_OPTS="$JAVA_OPTS -XX:OnOutOfMemoryError=\"$restart_command\""
Generally what it does is JAVA_OPTS is constructed inside test1.sh and then used to run Java binary, which just writes PID in pidfile and then creates OOME.
Problem happens during execution, java can't understand what is a parameter and what is a class to run. I think it might be a problem of quoting, I tried different ways to escape JAVA_OPTS, but without any result. I'm either getting:
Unrecognized option: -9
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Or
Error: Could not find or load main class "-XX:OnOutOfMemoryError=kill
If I just take a value of JAVA_OPTS and put it manually in test.sh it runs perfectly.
Any ideas how can I change test1.sh to make it work? I think I tried almost every possible way of putting double and single quotes, but without any success. Also if I put restart_command in restart.sh file and use it instead of the variable, it works fine.
After running set -x I saw that shell modifies every single space character to ' ' - adds ' on both sides. Escaping doesn't gives any result. Any idea how to avoid this? So final commend is:
+ java -Xmx10m '"-XX:OnOutOfMemoryError=kill' '$(cat' 'test.pid);sleep' '2;/Users/davidt/test/TestMemory/bin/test.sh' '")' -Des.pidfile=test.pid TestMemory
Update
I can run simplified command successfully
java "-XX:OnOutOfMemoryError=echo 'Ups'" $es_params TestMemory
But it seems a general problem, shell just hates spaces into variables I guess:
JAVA_OPTS="\"-XX:OnOutOfMemoryError=echo 'Ups'\""
set -x
java $JAVA_OPTS TestMemory
This script fails and the last line is interpreted as:
java '"-XX:OnOutOfMemoryError=echo' ''\''Ups'\''"' TestMemory
I tried different options to escape
This is a shell problem. Based on the evidence, I'd say that one of the ; characters ... and possibly some why space ... is being interpretted by the shell when you don't want / need this to happen.
If you run set -x in the shell before running the command that is trying to start the JVM, you will see the actual command that is being used.
It seems shell translates every single space to ' ',
Not exactly. The single quotes are inserted by the shell into the output you are getting from set -x. They simply indicating where the argument boundaries are. They are not really there ... and they are certainly NOT being passed to the java command.
Any idea how to [a]void it?
What you need to do is start from the (final) command that you are trying execute ...
java -Xmx10m -XX:OnOutOfMemoryError="kill NNNN;sleep 2;/Users/davidt/test/TestMemory/bin/test.sh" -Des.pidfile=test.pid TestMemory
... and work backwards, so that the shell variables, expansions and escaping give you what you need.
The other thing to note is that this:
java -Xmx10m -XX:OnOutOfMemoryError="kill $(cat test.pid); ..."
probably won't work. The kill $(cat test.pid) command is using shell syntax and requires shell functionality to interpolate the contents of the PID file. I doubt that the JVM is going to know what to do with that. (Or more accurately. It will do what you have literally told it to do, but that will not be what you want ...)
If you really need to interpolate the pid file content when the restart command is run as you appear to be trying to do, then suggest that turn the restart command into a free-standing shell script, and set the file mode so that it is executable. It will be simpler and a lot easier to get working.
As a general piece of advice, is is a bad idea to be too clever with shell scripts. The exact semantics of variable expansion and command parsing are rather tricky, and it is easy to get yourself really confused ... if you are trying to do this at multiple levels.
I ended up put the script I wanted to execute in a separate file and gave it as a parameter to JVM to execute when OOME happens.
echo "echo 'UPS'" >> oome_happened.sh
JAVA_OPTS="\"-XX:OnOutOfMemoryError='oome_happened.sh'\""
set -x
java $JAVA_OPTS TestMemory
Like #DaTval said, you should put the command in a script. The script should be someting like.
#!/bin/bash
kill -9 $PPID
Kill the caller of scripts.
I have a Java program which I'd like to call inside a linux shell script. The Java program takes a user input from the command line.
I read somewhere that I can use echo to mimic user input as follows:
java myProgram
echo 1000
echo
However this doesn't work for me, the program is still waiting for the user input. Is there something I'm doing wrong? I can't imagine this is a difficult task.
You can use echo, but in a pipeline.
echo 1000 | java myProgram
If you want to send a file, you can use cat:
cat file.txt | java myProgram
Why not just pass in the value as an argument
java myProgram 1000
I think you should find the process id of your java process and then write to its /proc directory.
Say the id of the Java process is 4321, then output to
/proc/4321/fd/0