How to chain nohup commands to run in succession? - bash

I would like to run a bunch of nohup commands in succession and store the output in different files.
I came up with this:
$ nohup python3 foo.py 0 &> nohup-0-foo.out && \
nohup python3 foo.py 1 &> nohup-1-foo.out && \
nohup python3 foo.py 2 &> nohup-2-foo.out && \
nohup python3 foo.py 3 &> nohup-3-foo.out && \
nohup python3 foo.py 4 &> nohup-4-foo.out &
But this seems not to work (python3 foo.py 0 is executed, but it stop after this).
Q: How can I make the commands run in succession?

Couple ways.
One, throw them all in a file -
$: cat script
#!/bin/bash
for i in {0..4}; do python3 foo.py $i &> $i.out || break; done
And run that.
nohup ./script > script.out &
Two, if you just want to to it on the command line:
{ trap '' HUP; for i in {0..4}; do python3 foo.py $i &> 0.out || break; done; } &
or
{ trap '' HUP;
python3 foo.py 0 &> 0.out &&
python3 foo.py 1 &> 1.out &&
python3 foo.py 2 &> 2.out &&
python3 foo.py 3 &> 3.out &&
python3 foo.py 4 &> 4.out & # why running *this one* in background?
}
Basically what nohup does is trap hangup signals and make sure you have all your output logged, so there should be little difference.

Related

shell script to execute a nohup task inside a docker

referred
Tried the following, to execute the below nohup commands inside a container,
nohup sh $KAFKA_HOME/bin/connect-standalone.sh $KAFKA_HOME/config/connect-standalone-mongo.properties $KAFKA_HOME/config/connect-mongo-sink.properties &
nohup /bin/bash $KAFKA_HOME/bin/connect-standalone.sh $KAFKA_HOME/config/connect-standalone-mongo.properties $KAFKA_HOME/config/connect-mongo-sink.properties &
And tried the below as well,
declare -a parameters=( "/opt/kafka/config/connect-standalone-mongo.properties" "/opt/kafka/config/connect-mongo-sink.properties")
for parameter in "${parameters[#]}"
do
echo "$1" > "/tmp/test02.txt"
nohup /bin/sh $KAFKA_HOME/bin/connect-standalone.sh -p $parameter 1> ${parameter}_nohup.out 2> ${parameter}_nohup.err &
#message received
echo "$1" > "/tmp/test03.txt"
done[referred the following link as well][1]
when I tried the below I am getting and empty out file,
$(nohup .$KAFKA_HOME/bin/connect-standalone.sh $KAFKA_HOME/config/connect-standalone-mongo.properties $KAFKA_HOME/config/connect-mongo-sink.properties > out.txt &)
The below way of scripting works for me!!!!!!!!!
ex=' /opt/kafka/bin/connect-standalone.sh /opt/kafka/config/connect-standalone-mongo.properties /opt/kafka/config/connect-mongo-sink.properties > /opt/kafka/kafka-mongo-info.out 2> /opt/kafka/kafka-mongo-error.err &'
while true
do
# nohup $ex 1> nohup_kms.out 2> nohup_kms.err | tee -a /var/log/my_uber_script.log
# nohup $ex 1> nohup_kms.out 2> nohup_kms.err
done
you can try any one inside the loop

Escaping character from Windows to WSL

I am trying to send the following line :
trap 'test -n "$SSH_AUTH_SOCK" && eval `/usr/bin/ssh-agent -k`' 0
to a file from Windows to WSL.
Here is what I've got so far :
bash -c "echo -e 'trap test -n \"\$SSH_AUTH_SOCK\" && eval \`/usr/bin/ssh-agent -k\` 0' >> $HOME/test"
I can't find a way to quote the trap argument. Thanks in advence for your help.
A colleague of mine found a solution : use a fonction
bash -c "echo -e 'onexit() { test -n \"\$SSH_AUTH_SOCK\" && eval \`/usr/bin/ssh-agent -k\`; }' > $HOME/testA"
bash -c "echo -e trap onexit 0 >> $HOME/testA"

Get command used to start a script

How to get the command previously used to start a shell script?
for example:
nohup /script_name.sh &
Inside the script itself, how to check if "nohup" has been used?
Thanks.
You want to use the $_ parameter in your script.
Example: shell.sh
#!/bin/bash
echo $_;
user#server [~]# sh shell.sh
/usr/bin/sh
user#server [~]#
Additionally:
If you want to get rid of that full path - /usr/bin/sh - utilize basename command.
#!/bin/bash
echo `basename $_`;
user#server [~]# sh shell.sh
sh
user#server [~]#
well that depends on the script in question.There're many ways to execute a script like:
./<scriptname> #chmod 700 <scriptname> should be done before executing this script
bash <scriptname> # provided bash is used for executing the script.
or if you just want to get the name of script2 in script1, then use sed or awk for parsing the script1 with regular expression => /script2/.
Try this:
cat <script1> | awk '{ if( $0 ~ /^[^#].* \/scriptname.sh/ ){ print $1}}'
#codebaus thanks, doing something like this works but using strace definitely not.
#!/bin/bash
# echo $_
# echo $0
if grep "sh" $_ >/dev/null ; then
exit 1
fi ;
echo "string" ;
I believe you want to run this?:
#!/bin/bash
# echo $_
# echo $0
if grep "sh" $_ 2> /dev/null ; then
exit 1
fi ;
echo "string";
user#server [~]# sh shell.sh
Binary file /usr/bin/sh matches
user#server [~]#
Not sure what you are trying to accomplish in the end game. But $_ should give you what you need based on your initial question.
Additionally:
As I did not answer your strace comment, apologies. Based on the previous code above.
strace sh shell.sh
wait4(-1, Binary file /usr/bin/strace matches
[{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 874
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
--- SIGCHLD (Child exited) # 0 (0) ---

Multiple sequential jobs in a shell script to be cronned in a conditional manner

I have 31 shell scripts named runner1.sh..runner31.sh . I need to create a cron job and put all of these .sh script run sequential with the condition that they must run if they are not already running and meanwhile if runnerX fails it should stop and not start running runnerX+1.
I've write a shell script for aggregation of these tasks as follow, but I'm not sure whether this is the correct solution:
ps -ef |grep -i grep | grep runner1.sh && echo "not to start" && sh runner1.sh && sh runner2.sh && sh runner3.sh && sh runner4.sh && sh runner5.sh && sh runner6.sh && sh runner7.sh && sh runner8.sh && sh runner9.sh && sh runner10.sh && sh runner11.sh && sh runner12.sh && sh runner13.sh && sh runner14.sh && sh runner15.sh && sh runner16.sh && sh runner17.sh && sh runner18.sh && sh runner19.sh && sh runner20.sh && sh runner21.sh && sh runner22.sh && sh runner23.sh && sh runner24.sh && sh runner25.sh && sh runner26.sh && sh runner27.sh && sh runner28.sh && sh runner29.sh && sh runner30.sh && sh runner31.sh
Please tell me whether this method is correct or the solution is something else.
So you have a series of runnerX.sh scripts that you need to invoke sequentially.
for i in $(seq 1 31); do
sh runner$i.sh || break
done
This covers running them in sequential order, and not running the next one of the prior one fails.
To make sure that the basic runner1.sh is not running, you do:
pid=$(ps -fe | grep '[r]unner1.sh' | awk '{print $2}')
or
pid=$(pgrep runner1.sh)
or any of a wide variety of mechanisms for detecting the pid of runner1.sh
combined, you surround the for loop with an:
if [ -z "$pid" ]; then
# do for here
:
fi

Send commands to a GNU screen

I have a GNU screen named demo, I want to send commands to it. How do I do this?
screen -S demo -X /home/aa/scripts/outputs.sh
yeilds No screen session found.
and doing screen -ls shows that it isn't running.
If the Screen session isn't running, you won't be able to send things to it. Start it first.
Once you've got a session, you need to distinguish between Screen commands and keyboard input. screen -X expects a Screen command. The stuff command sends input, and if you want to run that program from a shell prompt, you'll have to pass a newline as well.
screen -S demo -X stuff '/home/aa/scripts/outputs.sh
'
Note that this may be the wrong approach. Are you sure you want to type into whatever is active in that session? To direct the input at a particular window, use
screen -S demo -p 1 -X stuff '/home/aa/scripts/outputs.sh
'
where 1 is the window number (you can use its title instead).
To start a new window in that session, use the screen command instead. (That's the screen Screen command, not the screen shell command.)
screen -S demo -p 1 -X screen '/home/aa/scripts/outputs.sh'
I put this together to capture the output from the commands. It also handles stdin if you want to pipe some input.
function xscreen {
# Usage: xscreen <screen-name> command...
local SCREEN_NAME=$1
shift
# Create screen if it doesn't exist
if ! screen -list | grep $SCREEN_NAME >/dev/null ; then
screen -dmS $SCREEN_NAME
fi
# Create I/O pipes
local DIR=$( mktemp -d )
local STDIN=$DIR/stdin
local STDOUT=$DIR/stdout
local STDERR=$DIR/stderr
mkfifo $STDIN $STDOUT $STDERR
trap 'rm -f $STDIN $STDOUT $STDERR; rmdir $DIR' RETURN
# Print output and kill stdin when both pipes are closed
{ cat $STDERR >&2 & cat $STDOUT & wait ; fuser -s -PIPE -k -w $STDIN ; } &
# Start the command (Clear line ^A^K, enter command with redirects, run with ^O)
screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; } <$STDIN 1> >(tee $STDOUT) 2> >(tee $STDERR >&2)$(echo -ne '\015')"
# Forward stdin
cat > $STDIN
# Just in case stdin is closed
wait
}
Taking it a step further, it can be useful to call this function over ssh:
ssh user#host -n xscreen somename 'echo hello world'
Maybe combine it with something like ssh user#host "$(typeset -f xscreen); xscreen ..." so you don't have to have the function already defined on the remote host.
A longer version in a bash script that handles the return status and syntax errors:
#!/bin/bash
function usage {
echo "$(basename $0) [[user#]server:[port]] <screen-name> command..." >&2
exit 1
}
[[ $# -ge 2 ]] || usage
SERVER=
SERVERPORT="-p 22"
SERVERPAT='^(([a-z]+#)?([A-Za-z0-9.]+)):([0-9]+)?$'
if [[ "$1" =~ $SERVERPAT ]]; then
SERVER="${BASH_REMATCH[1]}"
[[ -n "${BASH_REMATCH[4]}" ]] && SERVERPORT="-p ${BASH_REMATCH[4]}"
shift
fi
function xscreen {
# Usage: xscreen <screen-name> command...
local SCREEN_NAME=$1
shift
if ! screen -list | grep $SCREEN_NAME >/dev/null ; then
echo "Screen $SCREEN_NAME not found." >&2
return 124
# Create screen if it doesn't exist
#screen -dmS $SCREEN_NAME
fi
# Create I/O pipes
local DIR=$( mktemp -d )
mkfifo $DIR/stdin $DIR/stdout $DIR/stderr
echo 123 > $DIR/status
trap 'rm -f $DIR/{stdin,stdout,stderr,status}; rmdir $DIR' RETURN
# Forward ^C to screen
trap "screen -S $SCREEN_NAME -p0 -X stuff $'\003'" INT
# Print output and kill stdin when both pipes are closed
{
cat $DIR/stderr >&2 &
cat $DIR/stdout &
wait
[[ -e $DIR/stdin ]] && fuser -s -PIPE -k -w $DIR/stdin
} &
READER_PID=$!
# Close all the pipes if the command fails to start (e.g. syntax error)
{
# Kill the sleep when this subshell is killed. Ugh.. bash.
trap 'kill $(jobs -p)' EXIT
# Try to write nothing to stdin. This will block until something reads.
echo -n > $DIR/stdin &
TEST_PID=$!
sleep 2.0
# If the write failed and we're not killed, it probably didn't start
if [[ -e $DIR/stdin ]] && kill $TEST_PID 2>/dev/null; then
echo 'xscreen timeout' >&2
wait $TEST_PID 2>/dev/null
# Send ^C to clear any half-written command (e.g. no closing braces)
screen -S $SCREEN_NAME -p0 -X stuff $'\003'
# Write nothing to output, triggers SIGPIPE
echo -n 1> $DIR/stdout 2> $DIR/stderr
# Stop stdin by creating a fake reader and sending SIGPIPE
cat $DIR/stdin >/dev/null &
fuser -s -PIPE -k -w $DIR/stdin
fi
} &
CHECKER_PID=$!
# Start the command (Clear line ^A^K, enter command with redirects, run with ^O)
screen -S $SCREEN_NAME -p0 -X stuff "$(echo -ne '\001\013') { $* ; echo \$? > $DIR/status ; } <$DIR/stdin 1> >(tee $DIR/stdout) 2> >(tee $DIR/stderr >&2)$(echo -ne '\015')"
# Forward stdin
cat > $DIR/stdin
kill $CHECKER_PID 2>/dev/null && wait $CHECKER_PID 2>/dev/null
# Just in case stdin is closed early, wait for output to finish
wait $READER_PID 2>/dev/null
trap - INT
return $(cat $DIR/status)
}
if [[ -n $SERVER ]]; then
ssh $SERVER $SERVERPORT "$(typeset -f xscreen); xscreen $#"
RET=$?
if [[ $RET == 124 ]]; then
echo "To start screen: ssh $SERVER $SERVERPORT \"screen -dmS $1\"" >&2
fi
exit $RET
else
xscreen "$1" "${#:2}"
fi

Resources