multi-threading in bash script and echo pids from loop - arrays

I want to run a command with different arguments in multi-threading form,
What I tried is:
#!/bin/bash
ARG1=$1
ARG2=$2
ARG3=$3
for ... #counter is i
do
main command with ARG1 ARG2 ARG3 & a[i]=$!
done
wait `echo ${a[#]}`
I used & a[i]=$! in for loop and wait $(echo ${a[#]}) after for loop. I want my bash to wail till all threads finish then echo their pid for me...
But when I run my script after some time it waits.
Thank you

I think you want this:
#!/bin/bash
for i in 0 1 2
do
sleep 3 & a[$i]=$!
done
wait
echo ${a[#]}
You are missing the $ on the array index $i in your script. Also, you don't need to say which PIDs you are wating for if you are waiting for all of them. And you also said you wanted to see the list of PIDs at the end.

Related

Append data read from a file onto a bash array [duplicate]

Bash allows to use: cat <(echo "$FILECONTENT")
Bash also allow to use: while read i; do echo $i; done </etc/passwd
to combine previous two this can be used: echo $FILECONTENT | while read i; do echo $i; done
The problem with last one is that it creates sub-shell and after the while loop ends variable i cannot be accessed any more.
My question is:
How to achieve something like this: while read i; do echo $i; done <(echo "$FILECONTENT") or in other words: How can I be sure that i survives while loop?
Please note that I am aware of enclosing while statement into {} but this does not solves the problem (imagine that you want use the while loop in function and return i variable)
The correct notation for Process Substitution is:
while read i; do echo $i; done < <(echo "$FILECONTENT")
The last value of i assigned in the loop is then available when the loop terminates.
An alternative is:
echo $FILECONTENT |
{
while read i; do echo $i; done
...do other things using $i here...
}
The braces are an I/O grouping operation and do not themselves create a subshell. In this context, they are part of a pipeline and are therefore run as a subshell, but it is because of the |, not the { ... }. You mention this in the question. AFAIK, you can do a return from within these inside a function.
Bash also provides the shopt builtin and one of its many options is:
lastpipe
If set, and job control is not active, the shell runs the last command of a pipeline not executed in the background in the current shell environment.
Thus, using something like this in a script makes the modfied sum available after the loop:
FILECONTENT="12 Name
13 Number
14 Information"
shopt -s lastpipe # Comment this out to see the alternative behaviour
sum=0
echo "$FILECONTENT" |
while read number name; do ((sum+=$number)); done
echo $sum
Doing this at the command line usually runs foul of 'job control is not active' (that is, at the command line, job control is active). Testing this without using a script failed.
Also, as noted by Gareth Rees in his answer, you can sometimes use a here string:
while read i; do echo $i; done <<< "$FILECONTENT"
This doesn't require shopt; you may be able to save a process using it.
Jonathan Leffler explains how to do what you want using process substitution, but another possibility is to use a here string:
while read i; do echo "$i"; done <<<"$FILECONTENT"
This saves a process.
This function makes duplicates $NUM times of jpg files (bash)
function makeDups() {
NUM=$1
echo "Making $1 duplicates for $(ls -1 *.jpg|wc -l) files"
ls -1 *.jpg|sort|while read f
do
COUNT=0
while [ "$COUNT" -le "$NUM" ]
do
cp $f ${f//sm/${COUNT}sm}
((COUNT++))
done
done
}

Run Bash Command At X Time and Terminate for X Time

Hi im working on a simple bash coding i don't know how to accomplish this and this might be easy for you guys please help.
I have a simple program on file.sh
#!/bin/bash
./program
This ./program is a compiled version of C program which i complied using GCC im trying to use at in bash script to execute this program for few seconds and then terminate that after x interval time and restart again.
I hope you got my point?
Example: Run file.sh for 10 sec and I'll display the result from ./program C program and then after 10 sec it will restart again.
The answer is, if I understand correctly, a combination of sleep and timout:
while :; do
timout 10s ./program
# display some results
sleep 10
done
You can use the sleep command. For example: exec ./program && sleep n where n is the time you want the command to sleep. If you want you could put it in a while loop inside an sh script and run it continuously.
To run it continuously until you close the terminal:
while true
do
echo "[CTRL+C] to stop..."
timeout 10s ./program
done

How to kill hidden process?

I have the following script.
#!/bin/bash
if [ "$EUID" -ne 0 ]
then
echo ''
echo -e "\e[1;31m Please run the script as root \e[0m"
echo ''
exit
fi
for run in {1..11}
do
echo -e '\e[1;32m Initializing AP in backfround... \e[0m'
sudo screen -dmS hotspot
sleep 5
# start the AP in background
echo -e '\e[1;32m Starting AP in backfround... \e[0m'
sudo screen -S hotspot -X exec ./start_hostapd.sh
sleep 20
# save PIDs for dmS
ps -ef | grep "dmS" | awk '{print $2}' > dms.log
sleep 1
# save PIDs for hostapd
ps -ef | grep "hostapd" | awk '{print $2}' > process.log
sleep 1
echo -e '\e[1;33m Running data... \e[0m'
for run in {1..10}
do # send 10 times
sudo /home/ubuntu/Desktop/send_data/run_data
sleep 1
done
echo -e "\e[1;31m Stopping sending... \e[0m"
sleep 2
echo -e "\e[1;31m Quiting hotspot... \e[0m"
sudo /home/ubuntu/Desktop/kill_dms/kill_dms
sleep 5
echo -e "\e[1;31m Stopping AP... \e[0m"
sudo /home/ubuntu/Desktop/kill_hostapd/kill_hostapd
sleep 5
echo -e '\e[1;31m Wiping dead screens... \e[0m'
echo
sudo screen -wipe
sudo screen -X -S hotspot quit
sleep 5
done
I use a bash script that starts the AP (hostapd) and then it executes some another commands. Unfortunately, once the AP is started, the next lines will not be executed anymore. To avoid this problem, in the Script I start the AP using screen command that allows to run AP in background and also it allows to execute next lines.
For each iteration in the for-loop, the AP must be restarted. For this purpose I write out the PIDs of screen and hostapd and then I call my C programs, which kill these processes. At last I use screen commands again to ensure that the AP in the background has been stopped and it can be started again.
This implementation works good. However, when the script comes to the end and all processes has been already killed, the AP disappears in other devices and after some minutes it appears again and it happens several times. Only the system reboot helps to stop the AP completely.
I use htop to find out the processes which runs AP. However, I can not find the processes. The htop says that there is no processes, which I created using script from above. This is right, because the script kills the processes once it is finished.
So, I suppose that there are hidden processes for my AP and I do not see them. Is there a way to find that hidden processes and kill them to stop the AP?
When I just start the AP in another terminal and then I stop it just using CTRL+C, the AP will be stopped and my devices do not see it anymore.
That's why I suppose that the screen starts a hidden process, which can not be found by htop or by other programs like htop.
If you don't need any hostap process at all, I'd rather use pkill instead of trusting the management of pids. Easiest usage should look like:
pkill -f hostap
pkill -f screen
If you'd want to use another signal like 9, use:
pkill -9 -f hostap
pkill -9 -f screen
https://linux.die.net/man/1/pkill

Giving inputs to an executed program automatically

I have a C program that I want to run without having to manually type commands into. I have 4 commands (5 if you count the one to exit the program) that I want given to the program and I don't know where to start. I have seen some stuff like
./a.out <<<'name'
to pass in a single string but that doesn't quite work for me.
Other issues I have that make this more difficult are that one of the commands will give an output and that output needs to be a part of a later command. If I had access to the source code I could just brute force in some loops and counters so I am trying to get a hold of it but for now I am stuck working without it. I was thinking there was a way to do this with bash scripts but I don't know what that would be.
In simple cases, bash script is a possibility: run the executable in coproc (requires version 4). A short example:
#!/bin/bash
coproc ./parrot
echo aaa >&${COPROC[1]}
read result <&${COPROC[0]}
echo $result
echo exit >&${COPROC[1]}
with parrot (a test executable):
#!/bin/bash
while [ true ]; do
read var
if [ "$var" = "exit" ]; then exit 0; fi
echo $var
done
For a more serious scenarios, use expect.

bash script to collect pids in array

Working on a simple bash script that I can use to ultimately tell me if a rogue process is running that we don't want - this one will ultimately be running with a different parent pid. a monitor of sorts. Where I'm having an issue is getting all the specific pids that I want into an array that I can perform some actions on. Script first:
#!/bin/bash
rmanRUNNING=`ps -ef|grep /etc/process/process.conf|egrep -v grep|wc -l`
if [ $rmanRUNNING -gt 0 ]
then
rmanPPID=( $(ps -ef|grep processname|egrep -v grep|egrep -v /etc/process/process.conf|awk '{ printf $3 }') )
for i in "${rmanPPID[#]}"
do
:
echo $i
done
fi
So, goal is to check for existence of the main process, this is the one running with the config file in it, the first variable tells me this. Next, if it's running (based on the count greather than 0) the intention is to populate an array with all the parent pids, excluding what would be determined as the main process (we don't need to analyze this one). So, in the array definition we get the list of processes, grep process name, egrep -v the grep output, also egrep -v the "main" process and then awk the parent pids then iterate through and attempt to echo each one individually (more would be done in this section, but it's not working). Unfortunately, when I output $i all of the parent pids are simply concatenated together in one long string. If I try to output a specific array item I get an empty output.
Obviously the question here is, what's wrong with my array definition that is preventing it from being declared as an array, or some other odd thing.
This is on RHEL, 6.2 on the test environment, probably 7 in production by the time this is live.
Full disclosure, I'm a monitoring engineer, not an SA - definitely not a bash scripter by nature!
Thanks in advance.
EDIT: just for clarity, an echo to screen of the PIDs is NOT the end desired output, it's just a simple way to test that I'm getting back what I'm expecting. Based on comment below I believe pgrep type output is the preferred output. In the end I'll be tying these pids back one at a time against the original process to ensure that it is the parent, and if it is not I'll spit out an error.
It's not so much $i that will be one concatenated number, as well as that your array is just a single element of that concatenated number. This is because the output of awk is concatenated together, without any separator.
If you simply add a space within awk, you may get what you want:
rmanPPID=( $(ps -ef|grep processname | ... | awk '{ printf "%d ", $3 }') )
or even simpler, use print instead of printf:
rmanPPID=( $(ps -ef|grep processname | ... | awk '{ print $3 }') )
(Thanks to Jonathan Leffler, see comment below.)

Resources