Bash - Start a new instance of a command in another terminal seperate from your current terminal - linux

I have a simple bash script (test.sh) set up like this:
#!/bin/bash
args=("$#")
if [[ ( ${args[0]} = "check_capture" ) ]]; then
watch -n 1 'ls -lag /home/user/capture0'
watch -n 1 'ls -lag /home/user/capture1'
watch -n 1 'ls -lag /home/user/capture2'
exit
fi
Files are continuously being written to these target locations capture 0, capture 1, and capture 3. I want to be able to watch these directories using ls command continuously on 3 seperate terminals, and once I run this script (test.sh) from the current terminal, I want it to exit.
Right now it is blocked by each wait, which I know is a blocking bash command waiting for user input control-c. Is there a way I can have the 3 watch commands be executed in seperate terminals then reach the exit statement?

You can start several instances of the terminal in background, each one running a command, like this:
if [[ ... ]]; then
xterm -e 'watch -n 1 "ls -lag /home/user/capture0"' &
xterm -e 'watch -n 1 "ls -lag /home/user/capture1"' &
...
exit
fi
Check man xterm:
-e program [ arguments ... ]
This option specifies the program (and its command line arguments) to be run in the xterm window. It also sets the window title and icon name to be the basename of the program being executed if neither -T nor -n are given on
the command line. This must be the last option on the command line.
The same option works also for xfce-terminal and gnome-terminal.
In addition, xterm (and others) also support setting the title of the window, position, size (called geometry), colors, fonts, and many, many other features.

Related

nohup append the executed command at the top of the output file

Let's say that we invoke the nohup in the following way:
nohup foo.py -n 20 2>&1 &
This will write the output to the nohup.out.
How could we achieve to have the whole command nohup foo.py -n 20 2>&1 & sitting at the top of the nohup.out (or any other specified output file) after which the regular output of the executed command will be written to that file?
The reason for this is for purely debugging purpose as there will be thousands of commands like this executed and very often some of them will crash due to various reasons. It's like a basic report kept in a file with the executed command written at the top followed by the output of the executed command.
A straightforward alternative would be something like:
myNohup() {
(
set +m # disable job control
[[ -t 0 ]] && exec </dev/null # redirect stdin away from tty
[[ -t 1 ]] && exec >nohup.out # redirect stdout away from tty
[[ -t 2 ]] && exec 2>&1 # redirect stderr away from tty
set -x # enable trace logging of all commands run
"$#" # run our arguments as a command
) & disown -h "$!" # do not forward any HUP signal to the child process
}
To define a command we can test this with:
waitAndWrite() { sleep 5; echo "finished"; }
...and run:
myNohup waitAndWrite
...will return immediately and, after five seconds, leave the following in nohup.out:
+ waitAndWrite
+ sleep 5
+ echo finished
finished
If you only want to write the exact command run without the side effects of xtrace, replace the set -x with (assuming bash 5.0 or newer) printf '%s\n' "${*#Q}".
For older versions of bash, you might instead consider printf '%q ' "$#"; printf '\n'.
This does differ a little from what the question proposes:
Redirections and other shell directives are not logged by set -x. When you run nohup foo 2>&1 &, the 2>&1 is not passed as an argument to nohup; instead, it's something the shell does before nohup is started. Similarly, the & is not an argument but an instruction to the shell not to wait() for the subprocess to finish before going on to future commands.

Bash script to detect last command runned in terminal

I have to make a script that print all commands used by user. So I try to make a script that will run in background and which deletes history and registers every command runned from that moment and echo it in a file. This is what I did but it doesn't work.
function add_new_command() {
nr=$(history | wc -l)
if [ $nr -eq 1 ]; then
comanda=$(history | head -n 1)
echo $comanda > mycommands
history -c
fi
}
history -c
while true
do
add_new_command
done
A much better approach is to use the built-in variables for controlling history.
history -c
BASH_HISTORY=mycommands
I made a change and i think it gonna work now. I added next 2 lines in ~/.bashrc:
shopt -s histappend
PROMPT_COMMAND="history -a;$PROMPT_COMMAND"
and now all command from more than 1 terminal are instantly copy in ~/.bash_history . so all i need to do is to copy that file.

How to write a shell script to open four terminals and execute a command in each?

So I'm trying to create a shell script to do open up four terminal windows (konsoles preferably) and run a command in each and then keep each of those terminals open so I can continue to execute commands in them if desired.
I tried following the instructions listed here:
How to create a shell script to launch 3 terminals and execute a set of commands in each?
and
How can I make a script that opens terminal windows and executes
commands in them?
and after trying those details the best I have is the following:
#!/bin/bash
# some older test, doesn't work and complains and I get this message on command line: "QApplication::qAppName: Please instantiate the QApplication object first"
# I also can't enter text after command executes
#echo "Hello World!"
#exec konsole --noclose -e cat ~/.aliases
# opens terminal but then I can't control terminal afterwards
xterm -hold -e "echo Hello My World"
# didn't do anything
#exit 0
# didn't do anything except make me type exit an extra time where I executed my shell script
#$SHELL
EDIT:
Using Roberto's answer I get four terminals like this, but I can't enter additional commands, notice how there is no prompt like "mycomputername> ":
EDIT 2:
I found an even better way to do what I want. The script below will execute the commands listed in the cmds array in a separate terminal. So echo 'hello1' will run in one terminal, and echo 'hello2' will run in another terminal. This will continue for as many commands listed in the cmds array
!/bin/bash
# Shell script to open terminals
# and execute a separate command in each
# Commands to run (one per terminal)
cmds=('echo 'hello1'', 'echo 'hello2'')
# Loop through commands, open terminal, execute command
for i in "${cmds[#]}"
do
xterm -e "$i && /bin/tcsh" &
done
Konsole
multiple windows
#!/usr/bin/env bash
konsole --noclose -e echo Hello terminal 1! &
konsole --noclose -e echo Hello terminal 2! &
konsole --noclose -e echo Hello terminal 3! &
konsole --noclose -e echo Hello terminal 4! &
multiple tabs
#!/usr/bin/env bash
konsole --noclose --new-tab -e echo Hello terminal 1! &
konsole --noclose --new-tab -e echo Hello terminal 2! &
konsole --noclose --new-tab -e echo Hello terminal 3! &
konsole --noclose --new-tab -e echo Hello terminal 4! &
You could use a "for" loop, and a "&" to run xterm in background:
#!/bin/bash
# some older test, doesn't work and complains and I get this message on command line: "QApplication::qAppName: Please instantiate the QApplication object first"
# I also can't enter text after command executes
#echo "Hello World!"
#exec konsole --noclose -e cat ~/.aliases
for i in 1 2 3 4
do
# opens terminal but then I can't control terminal afterwards
xterm -hold -e "echo Hello My World" &
done
# didn't do anything
#exit 0
# didn't do anything except make me type exit an extra time where I executed my shell script
#$SHELL
I found this to be quite easily:
#!usr/bin/env bash
echo "Enter the value of n:"
read n
for ((i = 0; i < n; i++ ))
do
xterm -hold -e <enter command> &
# In my case, I used :
# xterm -hold -e sar -P $i 2 5 &
done
And that's pretty much it! Have a good day :)
Note : For those who are newbies, we save this with a file name '.sh'. Also, please note that this will execute n different commands on n different terminals. If you want, you can execute the same command on every terminal, just remove $i from the in do .... done part ;)
On a Linux Mint mate distribution, this will run <commands> in 3 separated terminal windows:
$ cat START.sh
mate-terminal --execute bash -c "<command1>"
mate-terminal --execute bash -c "<command2>"
mate-terminal --execute bash -c "<command3>"
Killing START.sh won't terminate children <commands>.

bash passing strings to "gnome-terminal -e"

this question looks like Opening multiple tabs in gnome terminal with complex commands from a cycle, but I am looking for a more generic solution.
I have a C program that calls a script "xvi" with arguments. Each argument is originally enclosed within quotes (''') and each quote in an argument is isolated and back-slashed (this format is a prerequisite) ex:
xvi 'a file' 'let'\''s try another'
The script xvi must launch gnome-terminal with "-e vim args"
With xterm instead of gnome-terminal, this is easy because xterm assumes that "-e" is the last argument and passes all the tail to the shell, so the following is OK:
exec /usr/bin/xterm -e /usr/bin/vim "$#"
For gnome-terminal, "-e" is an option among others and we need to 'package' the whole command line in one argument. This is what I have done, which is OK: Enclose each argument within double quotes(\"arg\") and backslash any double quote within an argument:
cmd="/usr/bin/vim"
while [ "$1" != "" ] ; do
arg=`echo "$1" | sed -e 's/\"/\\\"/g'`
cmd="$cmd \"$arg\""
shift
done
exec gnome-terminal --zoom=0.9 --disable-factory -e "$cmd"
Again, this works fine and I am nearly happy with that.
Question: Is there any nicer solution, avoiding the loop?
Thanks
Untested, but you could probably finagle printf '%q' into doing the job:
exec gnome-terminal --zoom=0.9 --disable-factory -e "$(printf '%q ' "$#")"
I know this thread is old but recently I had a similar need and I created a bash script to launch multiple tabs and run different commands on each of them:
#!/bin/bash
# Array of commands to run in different tabs
commands=(
'tail -f /var/log/apache2/access.log'
'tail -f /var/log/apache2/error.log'
'tail -f /usr/local/var/postgres/server.log'
)
# Build final command with all the tabs to launch
set finalCommand=""
for (( i = 0; i < ${#commands[#]}; i++ )); do
export finalCommand+="--tab -e 'bash -c \"${commands[$i]}\"' "
done
# Run the final command
eval "gnome-terminal "$finalCommand
You just need to add your commands in the array and execute.
Gist link: https://gist.github.com/rollbackpt/b4e17e2f4c23471973e122a50d591602

awk output when run in background

Im wondering why awk print different output when run in background
My script:
#!/bin/bash
echo "Name of shell is $SHELL"
relase=`uname -r`
echo "Release is: $relase"
if [ $SHELL != "/bin/bash" ] || [ $relase != "3.13.0-32-generic" ] ; then
echo "Warning, different configuration"
fi
if [ $# -eq 0 ] ; then
echo "Insert name of shell"
read sname
else
sname=$1
fi
awk -v sname="$sname" 'BEGIN {FS=":"} {if ($7 == sname) print $1 }' </etc/passwd &
When i run awk without ampersand, output is:
petr#PetrLinux-VirtualBox:~/Documents$ ./script1 /bin/bash
Name of shell is /bin/bash
Release is: 3.13.0-32-generic
root
petr
but when i run awk with ampersand - in background, output is folowing:
petr#PetrLinux-VirtualBox:~/Documents$ ./script1 /bin/bash
Name of shell is /bin/bash
Release is: 3.13.0-32-generic
petr#PetrLinux-VirtualBox:~/Documents$ root
petr
First record (root) is not printed on single line. Please tell me why ańd if there is way how to print on single line while running on background. Thanks.
What you see is a mix of two outputs. The first output is of your shell, printing the command prompt (petr#PetrLinux-VirtualBox:~/Documents$). The second output is root from your script.
As your shell script runs in the background, you now have two processes writing to your terminal window: the bash (printing the prompt), and your script, printing the awk-output. This then just mixes up.
The only way to prevent that is to redirect the output of the script to a file or other device, instead of your console. For example:
$ ./script1 /bin/bash &> output.txt &
The output is the same. It just appears to be different because two processes write on the same channel (your terminal) and mix their output. One process is the awk script and the other is your shell which prints a new prompt.
There is no way to determine the precise point in which the output will switch from one process to the other. It can be different on different systems (with the same software), it can also depend on the load of the computer and lots of other things.
The only decent solution is to redirect the output into a different stream, e. g. a file using > outfile.

Resources