Run two xterm commands at the same time in BASH [duplicate] - bash

This question already has answers here:
How do you run multiple programs in parallel from a bash script?
(19 answers)
Closed 4 years ago.
I am trying to run two different programs in xterm windows from the same automation script. My current code looks like this:
#!/bin/bash/sh
echo "STARTING PROGRAM ONE"
# change into correct directory
cd ~/myProjects/ProgramOne
xterm -e myProg1 -a P1 &> /tmp/ProgramOne/P1.txt
echo "STARTING PROGRAM TWO"
# change into correct directory
cd ~/myProjects/ProjectTwo
xterm -e myProg2 -a P2 &> /tmp/ProgramTwo/P2.txt
# Code to kill the xterm process?
echo "******************************************"
echo "START AUTOMATION COMPLETE"
echo "******************************************"
What I am looking to accomplish is to have two separate programs, in different directories, run in two different xterm windows so I can demonstrate to the end user that the programs are running appropriately.
Currently, the first program executes fine, and when I Ctrl + C it, the second kicks off just fine. However, I would like both to execute at the same time.
I have looked at a few resources on SO but have not found anything to help me with this problem.
I am on a CentOS7 system, trying to automate this process. Any help or advice would be great.
Thanks!

Start them in the background and wait for them to finish:
#!/bin/bash/sh
echo "STARTING PROGRAM ONE"
# change into correct directory
cd ~/myProjects/ProgramOne
xterm -e myProg1 -a P1 &> /tmp/ProgramOne/P1.txt &
echo "STARTING PROGRAM TWO"
# change into correct directory
cd ~/myProjects/ProjectTwo
xterm -e myProg2 -a P2 &> /tmp/ProgramTwo/P2.txt &
# Code to kill the xterm process?
wait
echo "******************************************"
echo "START AUTOMATION COMPLETE"
echo "******************************************"

Related

How to suppress function output in Bash?

I wrote a little helper to start an Android emulator which looks like this:
# START ANDROID EMULATION
android-sim () {
if [[ -z "$1" ]]; then
echo "No Android device supplied as argument!"
return 1
fi
if [[ -d "$ANDROID_HOME" ]]; then
cd "$ANDROID_HOME/emulator" &>/dev/null
./emulator "#$1" &>/dev/null &
cd - &>/dev/null
else
echo "The variable ANDROID_HOME is not set to a correct directory!"
fi
}
I tried to suppress all the generated output with &>/dev/null. For the emulator itself I also tried to put the execution in the background.
But when I run the function I still get the following output:
# before exeuction
[09:11:48] sandrowinkler:~ $ android-sim pixel-29
[1] 23217
# after execution, I closed the emulator via GUI
[09:11:55] sandrowinkler:~ $
[1]+ Done ./emulator "#$1" &> /dev/null
(wd: /usr/local/share/android-sdk/emulator)
(wd now: ~)
According to this superuser post and this unix post I used the right way to silence the output. So what am I doing wrong here?
PS: I would also appreciate tips to improve my Bash code.
If the monitoring of the background job is not needed the double fork may be a solution.
( ./emulator "#$1" &>/dev/null & )
when the parent exit before the child process the child process is attached to process 1 so no more monitored by current shell.
also looking at the script, cd - could be avoided changing directory in the sub shell:
(
cd "$ANDROID_HOME/emulator"
./emulator "#$1" &
) &>/dev/null
because current shell will not be affected by subshell change directory
You've done it correctly. That output is not from your script, but from the shell, displaying information about the background process (the PID, the done message and the working directory when in ends).
If you redirect the input externally, like this:
andoroid-sim foo > log.txt
and after execution you open log.txt, you'll see what actually your program outputed (and those messages won't be there, even if they appear in the console).

Run bash script in background by default

I know I can run my bash script in the background by using bash script.sh & disown or alternatively, by using nohup. However, I want to run my script in the background by default, so when I run bash script.sh or after making it executable, by running ./script.sh it should run in the background by default. How can I achieve this?
Self-contained solution:
#!/bin/sh
# Re-spawn as a background process, if we haven't already.
if [[ "$1" != "-n" ]]; then
nohup "$0" -n &
exit $?
fi
# Rest of the script follows. This is just an example.
for i in {0..10}; do
sleep 2
echo $i
done
The if statement checks if the -n flag has been passed. If not, it calls itself with nohup (to disassociate the calling terminal so closing it doesn't close the script) and & (to put the process in the background and return to the prompt). The parent then exits to leave the background version to run. The background version is explicitly called with the -n flag, so wont cause an infinite loop (which is hell to debug!).
The for loop is just an example. Use tail -f nohup.out to see the script's progress.
Note that I pieced this answer together with this and this but neither were succinct or complete enough to be a duplicate.
Simply write a wrapper that calls your actual script with nohup actualScript.sh &.
Wrapper script wrapper.sh
#! /bin/bash
nohup ./actualScript.sh &
Actual script in actualScript.sh
#! /bin/bash
for i in {0..10}
do
sleep 10 #script is running, test with ps -eaf|grep actualScript
echo $i
done
tail -f 10 nohup.out
0
1
2
3
4
...
Adding to Heath Raftery's answer, what worked for me is a variation of what he suggested such as this:
if [[ "$1" != "-n" ]]; then
$0 -n & disown
exit $?
fi

AppleScript won't run shell script as is in Terminal

I have a .sh script that works fine if I run it in Terminal using "/Volumes/MEDIA/SERVER/SYNC.sh"
But I can not get it to run the same in AppleScript Editor using:
do shell script "/Volumes/MEDIA/SERVER/SYNC.sh"
Also tried the above with bash in front, sh in front.
The shell script (SYNC.sh)
#!/bin/bash
login="uhh"
pass="uhh"
host="uhh.com"
remote_dir='~/private/sync'
local_dir="/Volumes/MEDIA/_/SYNCING"
base_name="$(basename "$0")"
lock_file="/tmp/$base_name.lock"
trap "rm -f $lock_file" SIGINT SIGTERM
if [ -e "$lock_file" ]
then
echo "$base_name is running already."
exit
else
touch "$lock_file"
lftp -p 22 -u "$login","$pass" sftp://"$host" << EOF
set sftp:auto-confirm yes
set mirror:use-pget-n 5
mirror -c -P5 --Remove-source-files --log="/Volumes/MEDIA/SERVER/LOGS/$base_name.log" "$remote_dir" "$local_dir"
quit
EOF
# MOVE FINISHED FILES INTO DIRECTORY FOR CONVERSION
mv /Volumes/MEDIA/_/SYNCING/movies/* /Volumes/MEDIA/SEEDBOX/MOVIES
mv /Volumes/MEDIA/_/SYNCING/tvshows/* /Volumes/MEDIA/SEEDBOX/TVSHOWS
mv /Volumes/MEDIA/_/SYNCING/books/* /Volumes/MEDIA/SEEDBOX/BOOKS
mv /Volumes/MEDIA/_/SYNCING/music/* /Volumes/MEDIA/SEEDBOX/MOVIES
# SHOW COMPLETED NOTIFICIATION
osascript -e 'display notification "Sync completed" with title "SEEDB0X"'
rm -f "$lock_file"
trap - SIGINT SIGTERM
exit
fi
By not 'the same' what happens is only the
osascript -e 'display notification "Sync completed" with title "SEEDB0X"'
is run. With the script running through Terminal that only appears once syncing is done.
Thanks for any help!
Did you install lftp yourself? I don't have a Mac handy to check if it's in Mac OS X by default or not. If you installed it, then it probably isn't in the PATH of the AppleScript environment and the bash script can't find it when run from there.
If this is the case, then you'll have to either:
Fully qualify the path to 'lftp' (eg, "/usr/local/bin/lftp" or where ever it actually is)
or
Append to the PATH environment variable as used by AppleScript (or early in your bash script).
I think I'd go for option 1. Option 2 is overkill and more likely to adversely affect other things at other times.
PS. If you don't know where 'lftp' is installed, type 'which lftp' in the terminal.

Display a progress bar or spinner while a command is running in bash script [duplicate]

This question already has answers here:
Using Bash to display a progress indicator [duplicate]
(12 answers)
Closed 7 years ago.
I have a bash script that ends as follows:
trap "exit" INT
for ((i=0; i < $srccount; i++)); do
echo -e "\"${src[$i]}\" will be synchronized to \"${dest[$i]}\""
echo -e $'Press any key to continue or Ctrl+C to exit...\n'
read -rs -n1
#show_progress_bar()
rsync ${opt1} ${opt2} ${opt3} ${src[$i]} ${dest[$i]}
done
I need a command or a function such as show_progress_bar() that put . (a dot) in the stdout every one second while rsync command is running (or a rotating / that rotates as / - \ | sequence while rsync is running).
Is it possible? Do I need to wrote such function myself, or there is available scripts for this purpose?
It's not pretty, but it works:
~$ while true; do echo -n .; sleep 1; done & sleep 3; kill %-; wait; echo;
[1] 26255
...[1]+ Terminated while true; do
echo -n .; sleep 1;
done
(exchange the "sleep 3" for your actual work)
It works like this:
The while loop runs as a background job.
Meanwhile, your work ("sleep 3" in my example) runs in the foreground.
When the work is done, "kill %-" kills the echo loop.
Then we wait for the job to terminate, and echo a newline, just in case.
Like I said, it's not pretty. And there's probably a much better way to do it. :)
EDIT: For example, like the answer here: Using BASH to display a progress (working) indicator

Check if a nohup script is running or start it

we are running a tool on different machine by calling the shell script to run it,
the script is in background by using "nohup scriptname ", for some reasons which i don't know the script stops after some time, i want to make a script to keep on checking if the script is stopped and runs it again.
I have very little knowledge on shell script, but suddenly this requirement came and i searched on google but not getting proper answer, please help.
Here is a simple and working solution.
First, the script which has to be run again, let's call it bar.sh:
#! /bin/bash
echo "bar is living"
sleep 5
echo "bar is dying"
exit
Second, the script which runs bar.sh and watches for his death, called foo.sh:
#! /bin/bash
while true ; do
echo "Running bar ..."
./bar.sh &
echo "Waiting bar's termination"
wait
done
Now just type in the terminal:
$ chmod +x foo.sh bar.sh
$ ./foo.sh

Resources