Running commands in bash script in parallel with loop - bash

I have a script where I start a packet capture with tshark and then check whether the user has submitted an input text file.
If there is a file present, I need to run a command for every item in the file through a loop (while tshark is running); else continue running tshark.
I would also like some way to stop tshark with user input such as a letter.
Code snippet:
echo "Starting tshark..."
sleep 2
tshark -i ${iface} &>/dev/null
tshark_pid=$!
# if devices aren't provided (such as in case of new devices, start capturing directly)
if [ -z "$targets" ]; then
echo "No target list provided."
else
for i in $targets; do
echo "Attempting to deauthenticate $i..."
sudo aireplay-ng -0 $number -a $ap -c $i $iface$mon
done
fi
What happens here is that tshark starts, and only when I quit it using Ctrl+c does it move on to the if statement and subsequent loop.

Adding a & at the end of command executes the command in a new sub process. Mind you won't be able to kill it with ctlr + c
example:
firefox
will block the shell
firefox & will not block shell

Related

Corrupted mpeg-4 files when trying to put recording and pulling screenrecord videos in script

I want to write a script that initiates adb shell screenrecord in the background of my looping script. The looping script will be waiting at a menu waiting to read a 1 character user input.
When user presses any key, I want to automatically stop the screen-recording and pull the video file onto the user's computer.
On top of that, I will need to be able to place a countdown timer that will display on screen once the screenrecording commences, so they know how close to the 3min limit they are;
..using printf "\r%*s" ((0)) "$remainingTime" in a for loop for example.
This is the general idea of what I'm trying to do:
fileName="rec.$$.mp4"
record(){
adb shell screenrecord /sdcard/$fileName &
read -n 1 -s -r -p ''
#EOF represents where the screenrecord command expects the EOF signal
EOF
}
extract(){
adb pull sdcard/$fileName
}
record | wait && extract
exit
Using this method to interrupt the screenrecord (when replacing EOF with either return or kill "$childPID") may be the problem, but I cannot find anywhere how to accomplish the EOF interrupt to avoid corrupting the video file produced.
Right now, it does interrupt with EOF replaced, and it does also pull the file, but the pulled file is always corrupted.
Any ideas?
I tried adding wait 's and using various interrupt types to replace the EOF signal but to no avail.
This produces identical results; corrupted video file.
#!/bin/bash
set -x; clear
fileName="rec.$$.mp4"
record(){
adb shell screenrecord /sdcard/$fileName & childPID=$!
read -n 1 -s -r -p ''
kill "$childPID"
wait "$childPID"
}
extract(){
adb pull sdcard/$fileName
}
record | wait && extract; exit
Replacing the kill command with exit produces identical results as well.
After reading the character, kill the background process and wait for it to finish
fileName="rec.$$.mp4"
adb shell screenrecord /sdcard/"$fileName" &
childpid=$!
read -n 1 -s -r -p '' endRec
kill "$childpid"
wait "$childpid"
adb pull /sdcard/"$fileName"
Rather then using abd pull, just pipe the screenrecord to your file and save it on the fly.
fileName="rec.$$.mp4"
adb shell screenrecord - > "$fileName" &
childpid=$!
read -n 1 -s -r -p '' endRec
kill "$childpid"
wait "$childpid"
I have verified that manually entering the screenrecord command and using the EOF signal to interrupt the screenrecord command,
Create a fifo and send it.
tmpd=$(mktemp -d)
fifo="$tmpd/fifo"
mkfifo "$fifo"
adb shell screenrecord /sdcard/"$fileName" < "$fifo" &
childpid=$!
read -n 1 -s -r -p '' endRec
echo -e '\04' > "$fifo"
wait "$childpid"
rm -r "$tmpd" # cleanup
adb pull /sdcard/"$fileName"
Alternatively a bash coprocess could be good here.
Success! After much trial and error, I figured out a method to send eof to the screenrecord function running on the device's shell!
The solution was to trap traditional signals, and have the script send adb shell echo \04 whenever the exitScript function is called (note that is also the function that the most common signals will execute when caught).
#!/bin/bash
set -x; clear
fileName="rec.$$.mp4"
# make sure SIGINT always works even in presence of infinite loops
exitScript() {
trap - SIGINT SIGTERM SIGTERM SIGSTOP # clear the trap
adb shell echo \04; extract; exit
}; trap exitScript SIGINT SIGTERM SIGSTOP # set trap
record(){
adb shell screenrecord /sdcard/$fileName
}
extract(){
adb pull sdcard/$fileName
}
record && extract
exitScript
I also believe that not running screenrecord in a subshell might've helped to avoid corrupting the output file.
After making the screenrecord function loop until an interrupt occurs (then extracting in the background for continuous video sequences), and putting everything in a function to plug into my script, I think issue is fully resolved. Thanks for all your help!
#!/bin/bash
screenDVR(){
clear
read -r -p 'Enter the file path (or just drag the folder itself) of where you want to save the video sequences.. ' savePath
if [ ! "$savePath" = "" ]; then cd ~; cd "$savePath"; else printf "\nDefaulting to home directory\n"; cd ~; fi
# remove all files on device containing 'rec.'
adb -d shell rm -f *"/sdcard/rec."*
# make sure SIGINT always works even in presence of infinite loops
exitScript() {
trap - SIGINT SIGTERM SIGTERM # clear the trap
tput cnorm
adb -d shell echo \04; wait
extract
# remove all files on device containing 'rec.'
adb -d shell rm -f *"/sdcard/rec."*; wait
exit
}; trap exitScript SIGINT SIGTERM # set trap
extract(){
printf "\n%*s\n" $((0)) "Extracting.. $fileName .. to your computer!"
wait && adb pull sdcard/$fileName || return
}
record(){
printf "\n\n%*s\n\n" $((0)) "Use CTRL-C to stop the DVR.."
while true; do
tStamp="$(date +'%Hh%Mm%Ss')"
fileName="rec.$tStamp.$$.mp4"
printf "\n%*s\n\n" $((0)) "Starting new recording: $fileName"
adb -d shell screenrecord /sdcard/$fileName || adb shell echo \04
# running extract in a sub-process means the next video doesn't have any time-gap from the last
wait; extract & continue
done
}
record && wait && exitScript
}
(screenDVR) && printf "\ncontinue main loop\n"; exit

Unable to exit line in bash script

I am writing a script to start an application, grep for the word "server startup", exit and then execute the next command. But it would not exit and execute next cmd after condition is met. Any help?
#!/bin/bash
application start; tail -f /application/log/file/name | \
while read line ; do
echo "$line" | grep "Server startup"
if [ $? = 0 ]
then
echo "application started...!"
fi
done
Don't Use Tail's Follow Flag
Tail's follow flag (e.g. -f) will not exit, and will continue to follow the file until it receives an appropriate signal or encounters an error condition. You will need to find a different approach to tracking data at the end of your file, such as watch, logwatch, or periodic log rotation using logrotate. The best tool to use will depend a lot on the format and frequency of your log data.

Printed filesizes of files being written not updating?

I'm working on a shell script which does multiple tcpdumps in the background and then waits for the user to terminate. While waiting, I'd like for the script to print out the size of the folder where the .pcap files are being written. So far I've been getting the same size printed out even though the files are getting larger as the tcpdump command keeps running.
while true; do
echo ""
du -hcs <path>/<folder_name>
echo "Press enter to stop all traces: "
if read -rsn1 -t 5;
then
break
fi
echo ""
done
Try using watch
watch -n1 "du -hcs <path>/<folder_name>"
this will print the size each second
Turns out the problem was with the tcpdump command, adding -U before -w to tcpdump solved the problem.

Run a command in bash and keep it running until the user choose the no option

How do I make this work? I'm really trying to learn on my own.
But I'm really not getting this. I want to run a command in the
background and prompt a user whether they would like it to keep running
or not. If not, kill the command. I know I'm missing something. I'm just
not sure what.
Here's my code:
command > /dev/null 2>&1 &
echo
until [[ $REPLY =~ ^[Yy]$ ]] ;
do
echo
read -p "Would you like to stop the command [Yy/Nn]? " -n 1 -r
# Stop stop the command
killall -9 command
done
It is a little unclear what you want your loop frequency to be, but presuming you just want to block until the user types Yy, you can simply start command in the background, save its process ID (e.g. PID) using the bash special variable $!. Then simply loop until you get a Yy (which in bash, you can simply use the parameter expansion ${var,,} to evaluate var in lower-case). Upon received a Yy answer (using ans as the variable to store the response), you could do something similar to:
#!/bin/bash
command & >/dev/null 2>&1 # start command in background
cmdpid=$! # save the PID of command
ans=
while :; do # infinite loop until y or Y
printf "\nWould you like to stop the command (y/n)? "
read -n 1 -r ans # read ans
[ "${ans,,}" = 'y' ] && break
done
printf "\nkilling proc: %d\n" "$cmdpid"
kill $cmdpid # kill the PID
Example Use/Output
(without actually starting command above (as I have no clue what it is))
$ bash rununtil.sh
Would you like to stop the command (y/n)? k
Would you like to stop the command (y/n)? i
Would you like to stop the command (y/n)? l
Would you like to stop the command (y/n)? l
Would you like to stop the command (y/n)? Y
killing proc
Look things over and let me know if you have further questions.

Input to proprietary command prompt in shell script

I want to know how we can provide inputs to command prompts which change. I want to use shell scripting
Example where '#' is usual prompt and '>' is a prompt specific to my program:
mypc:/home/usr1#
mypc:/home/usr1# myprogram
myprompt> command1
response1
myprompt> command2
response2
myprompt> exit
mypc:/home/usr1#
mypc:/home/usr1#
If I understood correctly, you want to send specific commands to your program myprogram sequentially.
To achieve that, you could use a simple expect script. I will assume the prompt for myprogram is noted with myprompt>, and that the myprompt> symbol does not appear in response1 :
#!/usr/bin/expect -f
#this is the process we monitor
spawn ./myprogram
#we wait until 'myprompt>' is displayed on screen
expect "myprompt>" {
#when this appears, we send the following input (\r is the ENTER key press)
send "command1\r"
}
#we wait until the 1st command is executed and 'myprompt>' is displayed again
expect "myprompt>" {
#same steps as before
send "command2\r"
}
#if we want to manually interract with our program, uncomment the following line.
#otherwise, the program will terminate once 'command2' is executed
#interact
To launch, simply invoke myscript.expect if the script is in the same folder as myprogram.
Given that myprogram is a script, it must be prompting for input with something like while read IT; do ...something with $IT ...;done . Hard to say exactly how to change that script without seeing it. echo -n 'myprompt> would be the simplest addition.
can be done with PS3 and select construct
#!/bin/bash
PS3='myprompt> '
select cmd in command1 command2
do
case $REPLY in
command1)
echo response1
;;
command2)
echo response2
;;
exit)
break
;;
esac
done
Or with echo and read builtins
prompt='myprompt> '
while [[ $cmd != exit ]]; do
echo -n "$prompt"
read cmd
echo ${cmd/#command/response}
done

Resources