Bash script not ending because of the background processes - bash

I have a bash script as given below: It runs the python script with different arguments, each one as a background process (note that I have used '&')
#!/bin/bash
declare -a arr=("arg1" "arg2" "arg3")
for i in "${arr[#]}"
do
echo "$i"
python3 test.py $i &
echo "hi"
done
exit
The test.py file is as shown below:
import sys
print('Argument List:', str(sys.argv))
I tried to run the bash script with the command ./bash_script_test.sh.
Output is also right, but the script just doesnt end running. Plus the python code's output starts in a new command line. Refer below for the output.
arg1
hi
arg2
hi
arg3
hi
[root#csit-openstack1 risav]# Argument List: ['test.py', 'arg2']
Argument List: ['test.py', 'arg3']
Argument List: ['test.py', 'arg1']
Why is a new command line coming up and why is the shell script not exiting? Is it because of the use of & ? If yes, can somebody explain?

Take a cup of red color and a cup of green color and pour them into the same bucket. The result is a brown mess. The same happens with your terminal.
You have two processes, the foreground and the background process. Both write at the same time to the same terminal. The result is a mess. Background processes should write to log files instead.
Replace the line
python3 test.py $i &
with
python3 test.py $i > $i.log &
to give each background process its own log file.
If you want to merge the different sources, you have to use a tool like Syslog.
BTW: the script is ending. The last thing it does in the loop is printing "hi". And your output shows three times a "hi".

Related

Hacking exercise / How can I pass a new terminal command to an existing terminal command?

If we got this command line:
python file.py --gsgds dsgsdg --dg dgdg --dg 'gdgd'
And now, let's say we want to break this command and run another command while it is running, something like that:
python file.py --gsgds dsgsdg --dg dgdg --dg '`sleep 10`'
When I try to add a sleep 10 between the two quotes, it doesn't work. Please keep in mind that I must break the command between the two quotes. ('[inject here]')
Any ideas?
Let's take for example, we have bash shell running in the terminal. There are several characters which have special meaning in the bash shell. You can read more in the bash manual.
Let's take for example, ; in bash.
You can easily run sleep 10 after your python command using ;. Here's one way:
python file.py --gsgds dsgsdg --dg dgdg --dg ''; sleep 1; echo 'Done'
where you pass '; sleep 1; echo 'Done in the third arg.
Some shells add restriction on what characters can/ cannot be used so it's up to you to try out what works.

Getting last executed command name in bash script

In a bash script I want to get the name of the last command executed in terminal and store it in the variable for later use. I know that !:0 doesn't work in bash script, and I'm looking for some replacement of it.
For example:
#user enters pwd
> pwd
/home/paul
#I call my script and it show the last command
> ./last_command
pwd
this didn't help, it just prints empty line.
getting last executed command from script
Tell the shell to continuously append commands to the history file:
export PROMPT_COMMAND="history -a"
Put the following into your script:
#!/bin/bash
echo "Your command was:"
tail -n 1 ~/.bash_history
as far as I benefit the working one in my .bashrc;
export HISTCONTROL=ignoredups:erasedups
then do this, on console or in script respectively
history 2
cm=$(history 1)

How can I start a subscript within a perpetually running bash script after a specific string has been printed in the terminal output?

Specifics:
I'm trying to build a bash script which needs to do a couple of things.
Firstly, it needs to run a third party script that I cannot manipulate. This script will build a project and then start a node server which outputs data to the terminal continually. This process needs to continue indefinitely so I can't have any exit codes.
Secondly, I need to wait for a specific line of output from the first script, namely 'Started your app.'.
Once that line has been output to the terminal, I need to launch a separate set of commands, either from another subscript or from an if or while block, which will change a few lines of code in the project that was built by the first script to resolve some dependencies for a later step.
So, how can I capture the output of the first subscript and use that to run another set of commands when a particular line is output to the terminal, all while allowing the first script to run in the terminal, and without using timers and without creating a huge file from the output of subscript1 as it will run indefinitely?
Pseudo-code:
#!/usr/bin/env bash
# This script needs to stay running & will output to the terminal (at some point)
# a string that we need to wait/watch for to launch subscript2
sh subscript1
# This can't run until subscript1 has output a particular string to the terminal
# This could be another script, or an if or while block
sh subscript2
I have been beating my head against my desk for hours trying to get this to work. Any help would be appreciated!
I think this is a bad idea — much better to have subscript1 changed to be automation-friendly — but in theory you can write:
sh subscript1 \
| {
while IFS= read -r line ; do
printf '%s\n' "$line"
if [[ "$line" = 'Started your app.' ]] ; then
sh subscript2 &
break
fi
done
cat
}

bash show output only during runtime

I am trying to write a script that displays its output to the terminal only while it's running, much like the 'less' or 'ssh' commands.
When I launch said script, it would take over the whole terminal, print what it needs to print, and then when I exit the script, I would return to my terminal where the only record that my script has run will be the line that shows the command itself. When I scroll up, I don't want to see what my script output.
[snoopdougg#machine /home/snoopdougg/logs]$ ls
alog.log blog.log clog.log myScript.sh
[snoopdougg#machine /home/snoopdougg/logs]$ whoami
snoopdougg
[snoopdougg#machine /home/snoopdougg/logs]$ ./myScript.sh
[snoopdougg#machine /home/snoopdougg/logs]$
(Like nothing ever happened... but myScript.sh would have print things to the terminal while it was running).
How can I do this?
You're talking about the alternate screen, which you can access with a pair of terminal attributes, smcup and rmcup. Put this in a script and run it for a small demo:
tput smcup
echo hello
sleep 5
tput rmcup
Use screen:
screen ./myScript.sh

How can I monitor a bash script?

I am running a bash script that takes hours. I was wondering if there is way to monitor what is it doing? like what part of the script is currently running, how long did it take to run the whole script, if it crashes at what line of the script stopped working, etc. I just want to receive feedback from the script. Thanks!!!
from man page for bash,
set -x
After expanding each simple command, for command, case command, select command, or arithmetic for command, display the expanded value of PS4, followed by the command and its expanded arguments or associated word list.
add these to the start of your script,
export PS4='+{${BASH_SOURCE}:$LINENO} '
set -x
Example,
#!/bin/bash
export PS4='+{${BASH_SOURCE}:$LINENO} '
set -x
echo Hello World
Result,
+{helloworld.sh:6} echo Hello World
Hello World
Make a status or log file. For example add this inside your script:
echo $(date) - Ok >> script.log
Or for a real monitoring you can use strace on linux for see system call, example:
$ while true ; do sleep 5 ; done &
[1] 27190
$ strace -p 27190

Resources