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 "******************************************"
I have WSL bash running in a cmd. I don't use it for anything, it just hangs there to keep the WSL system alive.
When I start X applications:
bash -c "DISPLAY=:0 xmessage hello &"
I get this result:
I can close down the command window without any problems, but it's rather annoying.
How can run commands without getting this cmd window every time?
Here's a simpler solution, which, however, requires a WSH-based helper script, runHidden.vbs (see bottom section):
wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world'"
To apply #davv's own launch-in-background technique to avoid creating a new bash instance every time:
One-time action (e.g., at boot time): launch a hidden, stay-open bash window. This spawns 2 bash processes: the Windows bash.exe process that owns the console window, and the WSL bash process (owned by the WSL init singleton), which is then available for servicing background commands.
wscript .\runHidden.vbs bash # hidden helper instance for servicing background commands
For every X Window-launching command: Terminate each command with & to have it be run by the hidden WSL bash instance asynchronously, without keeping the invoking bash instance alive:
wscript .\runHidden.vbs bash -c "DISPLAY=:0 xmessage 'hello, world' &"
runHidden.vbs source code:
' Simple command-line help.
select case WScript.Arguments(0)
case "-?", "/?", "-h", "--help"
WScript.echo "Usage: runHidden executable [...]" & vbNewLine & vbNewLine & "Runs the specified command hidden (without a visible window)."
WScript.Quit(0)
end select
' Separate the arguments into the executable name
' and a single string containing all arguments.
exe = WScript.Arguments(0)
sep = ""
for i = 1 to WScript.Arguments.Count -1
' Enclose arguments in "..." to preserve their original partitioning, if necessary.
if Instr(WScript.Arguments(i), " ") > 0 then
args = args & sep & """" & WScript.Arguments(i) & """"
else
args = args & sep & WScript.Arguments(i)
end if
sep = " "
next
' Execute the command with its window *hidden* (0)
WScript.CreateObject("Shell.Application").ShellExecute exe, args, "", "open", 0
Even when launched from a GUI app (such as via the Run dialog invoked with Win+R), this will not show a console window.
If your system is configured to execute .vbs scripts with wscript.exe by default (wscript //h:wscript /s, which, I think, is the default configuration), you can invoke runHidden.vbs directly, and if you put it in your %PATH%, by filename (root) only: runHidden ....
Note that use of the script is not limited to console applications: even GUI applications can be run hidden with it.
There's another simple solution, it requires an external executable though. It has no dependencies and was recommended by aseering on GitHub.
you can launch bash via run.exe: run.exe bash.exe -c "<whatever Linux command>". (run.exe is available here: http://www.straightrunning.com/projectrun/ , make sure you download the 64-bit version, the 32-bit version will not be able to find or run bash).
With run on the search PATH, you can just call
run bash -c "DISPLAY=:0 xmessage hello"
So I just made this workaround for now. I really hope that there's a better way than this, but here it goes:
In the command prompt that lives purely to keep WSL alive, I have this script running:
wsl_run_server
#!/bin/bash
set -e
nc -kl 127.0.0.1 15150 | sh
And then I have this command to execute commands in background:
wsl_run_command
if ! pidof -x bin/wsl_run_server; then
echo wsl_run_server isnt running!
exit 1
fi
echo \($#\) \& | nc localhost 15150
from windows I then call:
bash -c "DISPLAY=:0 ~/bin/wsl_run_command xmessage hello"
There no longer is a need to have that command window pop up anymore with WSLg recently added to the mix. You just can call bash using WSLg, like so (I use Ubuntu currently in WSL):
wslg ~ -d Ubuntu bash
This will create a BASH session that will just sit there without being seen. Alternatively, you can do what I do and run a few services that stay running. I created a script that checks for running services, and if it doesn't find them running, will run them. Create the file in /usr/bin:
sudo touch /usr/bin/start-wsl-services
sudo nano /usr/bin/start-wsl-services
Past the following into the file:
#!/bin/bash
# Check for and run System-wide DBus service.
SERVICE="dbus-daemon"
if pgrep -x "$SERVICE" >/dev/null
then
pgrep -a "$SERVICE"
else
sudo /etc/init.d/dbus start
pgrep -a "$SERVICE"
fi
# Check for and run CUPS Printing Service.
SERVICE="cupsd"
if pgrep -x "$SERVICE" >/dev/null
then
pgrep -a "$SERVICE"
else
sudo /etc/init.d/cups start
pgrep -a "$SERVICE"
fi
# Check for and start Freshclam CLAMAV Update service.
SERVICE="freshclam"
if pgrep -x "$SERVICE" >/dev/null
then
pgrep -a "$SERVICE"
else
sudo /etc/init.d/clamav-freshclam start
pgrep -a "$SERVICE"
fi
# Check for and start SANED Scanner service.
SERVICE="saned"
if pgrep -x "$SERVICE" >/dev/null
then
pgrep -a "$SERVICE"
else
sudo /etc/init.d/saned start
pgrep -a "$SERVICE"
fi
# Check for and start screen-cleanup service.
SERVICE="screen-cleanup"
if pgrep -x "$SERVICE" >/dev/null
then
pgrep -a "$SERVICE"
else
sudo /etc/init.d/screen-cleanup start
pgrep -a "$SERVICE"
fi
# Check for and start Preload service.
SERVICE="preload"
if pgrep -x "$SERVICE" >/dev/null
then
pgrep -a "$SERVICE"
else
sudo /etc/init.d/preload start
pgrep -a "$SERVICE"
fi
# Prestart LibreOffice twice for faster loading.
#/usr/bin/libreoffice --terminate_after_init
#sleep 5
#/usr/bin/libreoffice --terminate_after_init
# Check for error, make sure all functions called and run, and pass the result on to calling process.
if [[ $? -ne 0 ]] ; then
exit 1
else
exit 0
fi
Save and exit the file, and then make it executable:
sudo chmod +x /usr/bin/start-wsl-services
I then call this using a shortcut that runs a startup script at startup. Or you can just run it manually. The command I use in the startup script is:
C:\Windows\System32\wslg.exe -d Ubuntu -- /usr/bin/start-wsl-services
The startup command script I use (named StartWSL.cmd) is as follows:
#echo off
echo Starting WSL Linux...
:RETRY
C:\Windows\System32\wslg.exe -d Ubuntu -- /usr/bin/start-wsl-services
REM - C:\Windows\System32\bash.exe -c '/usr/bin/start-wsl-services'
IF %ERRORLEVEL% NEQ 0 (GOTO RETRY)
REM - Allow time to see all results.
timeout /t 5 /nobreak >NUL
REM - Uncomment below line for troubleshooting.
REM - pause
exit 0
And that's how I now keep WSL running in the background on Windows 11, and similar to how I did it on Windows 10.
run command background
screen -dmS [name] [command]
example
screen -dmS gui bash -c "DISPLAY=:0 xmessage hello"
create a shortcut on windows desktop(run in wsl)
wslusc screen -dmS gui bash -c "DISPLAY=:0 xmessage hello"
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
I already know how to open a terminal in a bash with gnome-terminal and execute a program:
gnome-terminal -e ./OpenBTSCLI
But I also need that once open that program in the new terminal, write another command inside.
When a I tried to use echo, the message appear in the terminal where I run the bash.
I tried: gnome-terminal -e "bash -c './OpenBTSCLI && echo message'" that I find online but its not working, it only do the first part.
Anyone have an idea of how to resolve this? Thank you
I think it does the second command as well, but the new terminal closes as soon as the command's finished, so you don't see it. I reversed the order of quotes and added a 1s sleep at the end to allow seeing the echo.
gnome-terminal -e 'bash -c "./OpenBTSCLI && echo message && sleep 1"'
I've written a simple bash script that prompts for a file or directory path and opens it with exo-open, I've then assigned the script to a keyboard shortcut so that I can CTRL+SHIFT+ALT+O to open anything at anytime via a terminal prompt:
And the script:
#!/bin/bash
# CD to the home folder (not sure if this is needed, no harm either way)
cd ~/
# Request the filepath
echo -e "\e[1;31mEnter a file or directory:\e[00m"
read -e -i "~/" filename
# Convert ~/ to /home/username/
filename=`eval "echo $filename"`
echo -e "opening\e[1;32m" $filename "\e[00m"
# Open the file
exo-open "$filename"
echo "press enter to exit"
read enter
My problem is that the spawned program is linked to the terminal, when the terminal closes it takes the program with it - as a simple workaround I have another user prompt at the end to stop the terminal from closing; does anyone know how I could allow the terminal to close but keep the resulting program open?
Some ideas I've had / tried:
run disown $! after exo-open (didn't work)
use nohup (didn't work)
Run exo-open from the PPID (no idea how to do this)
At my wits end :-(
I had this answered by Xfce forum member ToC
http://forum.xfce.org/viewtopic.php?pid=25670
Turns out you can use setsid like so:
#!/bin/bash
# CD to the home folder (not sure if this is needed, no harm either way)
cd ~/
# Request the filepath
echo -e "\e[1;31mEnter a file or directory:\e[00m"
read -e -i "~/" filename
# Convert ~/ to /home/username/
filename=`eval "echo $filename"`
echo -e "opening\e[1;32m" $filename "\e[00m"
# Open the file
setsid exo-open "$filename"