How to tell if user selected "Run In Terminal" - linux

When you double-click a bash script, Ubuntu asks if the user wants to Display, Run, or Run In Terminal...
Is there a way within the script to determine if the user chose "Run In Terminal"?

Strictly speaking, you can't tell whether the user chose "Run In Terminal" after clicking on the script, or fired up a terminal and ran the script from there. But the commands below should help you, especially [ -t 2 ].
if [ -t 1 ]; then
echo "Standard output is a terminal."
echo "This means a terminal is available, and the user did not redirect the script's output."
fi
if [ -t 2 ]; then
echo "Standard error is a terminal." >&2
echo "If you're going to display things for the user's attention, standard error is normally the way to go." >&2
fi
if tty >/dev/null; then
echo "Standard input is a terminal." >$(tty)
echo "The tty command returns the name of the terminal device." >$(tty)
fi
echo "This message is going to the terminal if there is one." >/dev/tty
echo "/dev/tty is a sort of alias for the active terminal." >/dev/tty
if [ $? -ne 0 ]; then
: # Well, there wasn't one.
fi
if [ -n "$DISPLAY" ]; then
xmessage "A GUI is available."
fi

Here is an example:
#!/bin/bash
GRAND_PARENT_PID=$(ps -ef | awk '{ print $2 " " $3 " " $8 }' | \
grep -P "^$PPID " | awk '{ print $2 }')
GRAND_PARENT_NAME=$(ps -ef | awk '{ print $2 " " $3 " " $8 }' \
| grep -P "^$GRAND_PARENT_PID " | awk '{ print $3 }')
case "$GRAND_PARENT_NAME" in
gnome-terminal)
echo "I was invoked by gnome-terminal"
;;
xterm)
echo "I was invoked by xterm"
;;
*)
echo "I was invoked by someone else"
esac
Now, let me explain this in a little more details. In the case when script is executed by (in) a terminal, its parent process is always a shell itself. This is because terminal emulators run shell to invoke scripts. So the idea is to look at a grandparent process. If grandparent process is a terminal then you can assume that your script was invoked from a terminal. Otherwise, it was invoked by something else, for example, Nautilus, which is Ubuntu's default file browser.
The following command gives you a parent process ID.
ps -ef | awk '{ print $2 " " $3 " " $8 }' | grep -P "^$PPID " | awk '{ print $2 }'
And this command is giving you a name of your parent's parent process.
ps -ef | awk '{ print $2 " " $3 " " $8 }' | grep -P "^$GRAND_PARENT_PID " | awk '{ print $3 }'
And the final switch statement just compares grandparent process name with some known terminal emulators.

Never tried it, but probably this works:
if [ -t 1 ] ;
Although it would also be false if the output it piped...

Related

Shell script execution is failed with error " No such file or directory"

I Have written a shell script which simply show the swap memory usages from processes.
I have executed the script at my end successfully, but when I share this with client to execute it is getting failed at their end with below error.
$dzdo ./MemoryUsage.sh
dzdo: unable to execute ./MemoryUsage.sh : No such file or directory
What is the use of dzdo, because I have't used that command while executing script?
Below is the script file content:
#!/bin/bash
overall=0
for status_file in /proc/[0-9]*/status; do
swap_mem=$(grep VmSwap "$status_file" | awk '{ print $2 }')
if [ "$swap_mem" ] && [ "$swap_mem" -gt 0 ]; then
pid=$(grep Tgid "$status_file" | awk '{ print $2 }')
name=$(grep Name "$status_file" | awk '{ print $2 }')
printf "%s\t%20s\t%8s KB\n" "$pid" "$name" "$swap_mem"
fi
overall=$((overall+swap_mem))
done
printf "Total Swapped Memory: %18u KB\n" $overall

Bash Scripting checking for home directories

I'm trying to create a script to check if user accounts have valid home directories.
This is what i got at the moment:
#!/bin/bash
cat /etc/passwd | awk -F: '{print $1 " " $3 " " $6 }' | while read user userid directory; do
if [ $userid -ge 1000 ] && [ ! -d "$directory ]; then
echo ${user}
fi
done
This works. I get the expected output which is the username of the account with an invalid home directory.
eg. output
student1
student2
However, I am unable to make it so that ONLY if there is no issues with the valid home directories and all of them are valid, echo "All home directories are valid".
Didn't run it, but it should be something like:
#!/bin/bash
users=()
cat /etc/passwd | awk -F: '{print $1 " " $3 " " $6 }' | while read user userid directory; do
if [ $userid -ge 1000 ] && [ ! -d "$directory" ]; then
users=+("${user}")
fi
done
if test -n ${#users[#]} == 0; then
echo "All home directories are valid"
else
for (( i=0; i<${#users[#]}; i++ )); do echo "${users[$i]}" ; done
fi
You could set a flag, and unset it if you see an invalid directory. Or you could simply check whether your loop printed anything.
You have a number of common antipatterns which you'll want to avoid, too.
# Avoid useless use of cat
# If you are using Awk anyway,
# use it for user id comparison, too
awk -F: '$3 >= 1000 {print $1, $6 }' /etc/passwd |
# Basically always use read -r
while read -r user directory; do
# Fix missing close quote
if [ ! -d "$directory" ]; then
# Quote user
echo "$user"
fi
done |
# If no output, print default message
grep '^' >&2 || echo "No invalid directories" >&2
A proper tool prints its diagnostic output to standard error, not standard output, so I added >&2 to the end.

Centos add multiple interfaces from file to VLANs

I write script, that will create CentOS interfaces from file with list of IP addresses. In loop, i create file, next action, i add data for centos interfaces. Look:
from=/root/ip
inter=`cat /proc/net/dev | grep "eth0:\|venet0" | awk '{ print $1 }' | sed 's/://g'`
eth=`ifconfig | grep $inter | tail -1 | awk '{ print $1 }' | sed "s/$inter://g"`
echo "Last number of interface: $eth"
if [ "$eth" == "eth0" ]; then
eth_temp="-1"
else
eth_temp=$eth
fi
if [ "$inter" == "eth0" ]; then
echo "Name of interface: $inter"
echo "Add IP to interfaces"
if [ -f $from ]; then
for IP_TO_ETH in `grep -v ^# $from`; do
eth_temp=$(($eth_temp+1))
cent_int=`touch /etc/sysconfig/network-scripts/ifcfg-$inter:$eth_temp`
cat >> $cent_int <<END
DEVICE=eth0:$eth_temp
ONBOOT=yes
BOOTPROTO='static'
IPADDR=$IP_TO_ETH
NETMASK=255.255.255.0
END
done
else
echo "File does not exist"
fi
elif [ "$inter" == "venet0" ]; then
echo "Name of interface: $inter"
echo "This interface from OpenVZ. Not need to add"
else
echo "Other name of inteface"
fi
All ok. But it is not working. When i start bash/sh -x, i receive this:
cent.sh: line 28: $cent_int: ambiguous redirect
+ for IP_TO_ETH in '`grep -v ^# $from`'
+ eth_temp=61
++ touch /root/network-scripts/ifcfg-eth0:61
+ cent_int=
+ cat
cent.sh: line 28: $cent_int: ambiguous redirect
+ for IP_TO_ETH in '`grep -v ^# $from`'
+ eth_temp=62
++ touch /root/network-scripts/ifcfg-eth0:62
+ cent_int=
+ cat
Where i have error ? Please help. In ubuntu it is simply, because all will write in one file. But in CentOS, it is too difficult for me.
When you write:
variable=`command`
it sets the variable to the output of the command. But touch doesn't produce any output, so
cent_int=`touch /etc/sysconfig/network-scripts/ifcfg-$inter:$eth_temp`
assigns an empty string to cent_int. I think what you want is:
cent_int=/etc/sysconfig/network-scripts/ifcfg-$inter:$eth_temp
You don't need to use touch, since writing to the file with cat >> $cent_int will create the file if it doesn't already exist.

Switch case: Confusing error in "Syntax error: word unexpected (expecting "in")"

This is my code:
echo
echo "WELCOME"
echo "-------------------------------------------------"
while true
do
echo
echo "Select A Menu Option"
echo "1: Ancestry History"
echo "2: Who is Online"
echo "3: What Process Any User is Running"
echo "4: Exit"
read mOption
case $mOption in
1) echo
echo "The Ancestry Tree For Current Process is....";
ps -ef > processes
grep "ps -ef" processes > grepProcesses
awk '{print $2, $3}' processes > awkProcesses
PID=$(awk '{print $2}' grepProcesses)
echo $PID
SPID=$(awk '{print $3}' grepProcesses)
PID=$SPID
end=0
while [ $end != 1 ]
do
echo " | "
echo $SPID
PID=$SPID
SPID=$(grep ^"$PID " awkProcesses | cut -d' ' -f2)
if [ "$PID" = "1" ]
then
end=1
fi
done
rm processes
rm grepProcesses
rm awkProcesses
;;
2) echo
echo "Users Currently Online";
who | cut -d' ' -f1
;;
3) echo
echo "Select a Currently Online User to View their Processes:"
index=0
who | while read onlineUser
do
echo "$index-$onlineUser" who|cut -d' ' -f1>>userList
index=$((index+1))
done
awk '{ print $0 }' userList
read choice
if [ $choice ]
then
echo
echo ***Process Currently Running***
person=$(grep ^$choice userList |cut -d'-' -f2)
ps -ef >> process
grep $person process
else
echo You have made a mistake. Please start over.
fi
rm userList
rm process
;;
4) echo
echo "Exiting..."
exit 1;;
*)
echo
echo "Invalid Input. Try Again."
;;
esac
done
Each time I run it I just keep getting the syntax error "hmwk1.sh: 17: hmwk1.sh: Syntax error: word unexpected (expecting "in")"
I looked up different syntax examples and it seems that my code looks correct. But my trial and error gets me nowhere to fixing my code.
Could I be missing a parenthesis or quotation marks of some kind?
If you simply press return on the prompt
read mOption
case $mOption in
then $mOption is an empty token, making the shell see just
case in
which is a syntax error. If you add
test -z "$mOption" && continue
in the middle, if will repair that problem.

Trying out my first BASH script, keep getting unexpected end of file

I was trying to make a script that would pretty much automate this process:
http://knowledgelayer.softlayer.com/procedure/add-additional-ips-redhat
Wasn't too sure how well it would work, but didn't get too far before I could get the script to one. Below is the content of the script:
Editing with updated code:
Edit#2: Got it mostly working, however now it runs the loop and skips over the read propmt to get the static IP
#!/bin/bash
path=/etc/sysconfig/network-scripts/
echo "Let's get your IP added :)"
echo""
getnewip()
{
echo read -p "Enter the new IP Address you wish to add: " staticip
}
getserverinfo()
{
gateway=$(netstat -rn | sed -n 3p | awk '{print $2}')
netmask=$(ifconfig eth1 | grep -i 'netmask' | grep -v '127.0.0.1' | awk '{print $4}')
clone=$( ifconfig | grep eth1 | awk '{print $1}' | cut -d: -f2 )
}
rangechecks()
{
cd /etc/sysconfig/network-scripts/
ls ifcfg-eth1-range*
filename==$1
if [[ ! -f $filename ]]; then
touch "$filename"
echo "Created \"$filename\""
fi
digit=1
while true; do
temp_name=$filename-$digit
if [[ ! -f temp_name ]]; then
touch "$temp_name"
echo "Created $path\"$temp_name\""
digit=$((digit + 1 ))
fi
done
}
writeinterfacefile()
{
cat >> "/etc/sysconfig/network-scripts/$1" << EOF
IPADDR_START=$staticip
IPADDR_END=$staticip
NETMASK=$netmask
CLONENUM_START=$((clone+1))
EOF
echo ""
echo "Your information was saved in the file '$1'."
echo ""
}
{
clear
getserverinfo
echo ""
echo "Please verify this information: "
echo "Gateway Address: " "$gateway"
echo "Netmask: " "$netmask"
echo "Your new IP: " "$staticip"
echo ''
while true; do
read -p "Is this information correct? [y/N]" yn
case $yn in
[Yy]* ) $writeinterfacefile;;
[Nn]* ) print "$getserverinfo" && exit ;;
* ) echo 'Please enter Y or n';;
esac
done
}
I'm fairly new at scripting, so excuse the horrid syntax. My eye is on that EOF but I have no clue.
rangecheckshas no }, your while has no done...
You should indent your code. I started doing that, and noticed the error right away.
Other things:
Single quotes don't expand variables, '/etc/sysconfig/network-scripts//$1 won't do what you want it to.
echo "" is equivalent to echo.
foo='bar'; echo "blah" echo -n $foo will output 'blah echo -n bar'.
exit exits the script, I'm not sure that's what you think it does.
[y/N] usually means N by default (the capital letter).
Also, you then ask to enter Y or n. Be consistent!
When using a variable as a parameter, double quote it. This ensures it stays the way it is (as one parameter, and not expanded by the shell).
I can't see the closing curly brace of function rangechecks
Also, don't indent the shebang in the first line.

Resources