I'm trying to get this script to loop back and restart if the user inputs a response that does not match the choices allowed but then enters a correct response the second time around. I tried using continue, but it loops infinitely. Any thoughts?
`
#!/bin/bash
#Obtaing user selection and input
echo " Gathering list of users on this machine..."
sleep 2
echo "$( ls /Users )"
echo "From the list above, which user did you want to work with?"
read userSelection
echo "What is that user's password?"
#Hiding User's Password
stty -echo
read userSelectionPassword
stty echo
echo "Did you want [enable], [disable], or check the current [status] of Secure Token for $userSelection?"
read taskSelection
#Converting input to lowercase
taskSelectionLower=$(echo $taskSelection | tr '[:upper:]' '[:lower:]')
#Running commands
while [ true ]
do
if [[ $taskSelectionLower == "enable" ]]; then
echo "Enabling..."
echo "$(sysadminctl -adminUser AdminUser -adminPassword AdminPass -secureTokenOn $userSelection -password $userSelectionPassword)"
break
elif [[ $taskSelectionLower == "status" ]]; then
echo "Displaying $userSelection current Secure Token status..."
echo "$( sysadminctl -secureTokenStatus $userSelection )"
break
elif [[ $taskSelectionLower == "disable" ]]; then
echo "Disabling..."
echo "$(sysadminctl -adminUser AdminUser -adminPassword AdminPass -secureTokenOff $userSelection -password $userSelectionPassword)"
break
else
echo "Incorrect selection made..."
echo "Did you want [enable], [disable], or check the current [status] of Secure Token for $userSelection?"
read taskSelection
exit
fi
done
`
Attempted using continue at the end of the condition, but loops infinitely.
Expected outcome would be for the for loop to restart, allowing the user to input a correct response and get the correct output.
The select command was designed exactly for this sort of interactive script.
Some hopefully useful observations -
echo " Gathering list of users on this machine..."
sleep 2 # why?
This sleep seems to serve no purpose but to annoy the user.
echo "$( ls /Users )" # why?? Don't do this.
This is exactly the same as
ls /Users # same output. Keep it simple.
Also, since you are bash instead of sh, rather than
taskSelectionLower=$(echo $taskSelection | tr '[:upper:]' '[:lower:]')
try declaring the variable as lowercase -
declare -l taskSelectionLower
read taskSelectionLower
or handle it with parameter parsing syntax -
read taskSelectionLower
taskSelectionLower="${taskSelectionLower,,}"
but why let them possibly mistype at all?
Consider using a select statement.
Rather than building your own loop, presenting options, worrying about formatting, etc, let tools that already do that handle it for you.
My rewrite using echo to show the commands to be executed - take those out and it should run fine.
#!/bin/bash
cd /c/Users
echo "Please select a valid user from this system."
select u in */; do
if [[ -d "$u" ]]
then userSelection="${u%/}"; break
else echo "Please enter a number from the presented options."
fi
done # get just the username
cd $OLDPWD # if needed
admSet() { # no reason to ask for the password just to get status...
read -sp "what's $userSelection's password? " userSelectionPassword
echo # reading the password leaves the cursor on the previous line
echo sysadminctl -adminUser AdminUser -adminPassword AdminPass \
-secureToken$1 "$userSelection" -password "$userSelectionPassword"
}
select taskSelection in enable disable status; do # case is controlled
case "$taskSelection" in
status) echo "Displaying $userSelection current Secure Token status..."
echo sysadminctl -secureTokenStatus $userSelection ;;
enable) echo "Enabling..." ; admSet On ;;
disable) echo "Disabling..." ; admSet Off ;;
*) echo "Please enter a number from the presented options."
continue ;;
esac
break
done
In this particular case, I'd like to add a confirm in Bash for
Are you sure? [Y/n]
for Mercurial's hg push ssh://username#www.example.com//somepath/morepath, which is actually an alias. Is there a standard command that can be added to the alias to achieve it?
The reason is that hg push and hg out can sound similar and sometimes when I want hgoutrepo, I may accidentlly type hgpushrepo (both are aliases).
Update: if it can be something like a built-in command with another command, such as: confirm && hg push ssh://... that'd be great... just a command that can ask for a yes or no and continue with the rest if yes.
These are more compact and versatile forms of Hamish's answer. They handle any mixture of upper and lower case letters:
read -r -p "Are you sure? [y/N] " response
case "$response" in
[yY][eE][sS]|[yY])
do_something
;;
*)
do_something_else
;;
esac
Or, for Bash >= version 3.2:
read -r -p "Are you sure? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]
then
do_something
else
do_something_else
fi
Note: If $response is an empty string, it will give an error. To fix, simply add quotation marks: "$response". – Always use double quotes in variables containing strings (e.g.: prefer to use "$#" instead $#).
Or, Bash 4.x:
read -r -p "Are you sure? [y/N] " response
response=${response,,} # tolower
if [[ "$response" =~ ^(yes|y)$ ]]
...
Edit:
In response to your edit, here's how you'd create and use a confirm command based on the first version in my answer (it would work similarly with the other two):
confirm() {
# call with a prompt string or use a default
read -r -p "${1:-Are you sure? [y/N]} " response
case "$response" in
[yY][eE][sS]|[yY])
true
;;
*)
false
;;
esac
}
To use this function:
confirm && hg push ssh://..
or
confirm "Would you really like to do a push?" && hg push ssh://..
Here is roughly a snippet that you want.
Let me find out how to forward the arguments.
read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt == "y" || $prompt == "Y" || $prompt == "yes" || $prompt == "Yes" ]]
then
# http://stackoverflow.com/questions/1537673/how-do-i-forward-parameters-to-other-command-in-bash-script
else
exit 0
fi
Watch out for yes | command name here :)
Confirmations are easily bypassed with carriage returns, and I find it useful to continually prompt for valid input.
Here's a function to make this easy. "invalid input" appears in red if Y|N is not received, and the user is prompted again.
prompt_confirm() {
while true; do
read -r -n 1 -p "${1:-Continue?} [y/n]: " REPLY
case $REPLY in
[yY]) echo ; return 0 ;;
[nN]) echo ; return 1 ;;
*) printf " \033[31m %s \n\033[0m" "invalid input"
esac
done
}
# example usage
prompt_confirm "Overwrite File?" || exit 0
You can change the default prompt by passing an argument
To avoid explicitly checking for these variants of 'yes' you could use the bash regular expression operator '=~' with a regular expression:
read -p "Are you sure you want to continue? <y/N> " prompt
if [[ $prompt =~ [yY](es)* ]]
then
(etc...)
That tests whether the user input starts with 'y' or 'Y' and is followed by zero or more 'es's.
This may be a hack:
as in question In Unix / Bash, is "xargs -p" a good way to prompt for confirmation before running any command?
we can using xargs to do the job:
echo ssh://username#www.example.com//somepath/morepath | xargs -p hg push
of course, this will be set as an alias, like hgpushrepo
Example:
$ echo foo | xargs -p ls -l
ls -l foo?...y
-rw-r--r-- 1 mikelee staff 0 Nov 23 10:38 foo
$ echo foo | xargs -p ls -l
ls -l foo?...n
$
This may be a little too short, but for my own private use, it works great
read -n 1 -p "Push master upstream? [Y/n] " reply;
if [ "$reply" != "" ]; then echo; fi
if [ "$reply" = "${reply#[Nn]}" ]; then
git push upstream master
fi
The read -n 1 just reads one character. No need to hit enter. If it's not a 'n' or 'N', it is assumed to be a 'Y'. Just pressing enter means Y too.
(as for the real question: make that a bash script and change your alias to point to that script instead of what is was pointing to before)
Add the following to your /etc/bashrc file.
This script adds a resident "function" instead of an alias called "confirm".
function confirm( )
{
#alert the user what they are about to do.
echo "About to $#....";
#confirm with the user
read -r -p "Are you sure? [Y/n]" response
case "$response" in
[yY][eE][sS]|[yY])
#if yes, then execute the passed parameters
"$#"
;;
*)
#Otherwise exit...
echo "ciao..."
exit
;;
esac
}
read -r -p "Are you sure? [Y/n]" response
response=${response,,} # tolower
if [[ $response =~ ^(yes|y| ) ]] || [[ -z $response ]]; then
your-action-here
fi
No pressing enter required
Here's a longer, but reusable and modular approach:
Returns 0=yes and 1=no
No pressing enter required - just a single character
Can press enter to accept the default choice
Can disable default choice to force a selection
Works for both zsh and bash.
Defaulting to "no" when pressing enter
Note that the N is capitalsed. Here enter is pressed, accepting the default:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]?
Also note, that [y/N]? was automatically appended.
The default "no" is accepted, so nothing is echoed.
Re-prompt until a valid response is given:
$ confirm "Show dangerous command" && echo "rm *"
Show dangerous command [y/N]? X
Show dangerous command [y/N]? y
rm *
Defaulting to "yes" when pressing enter
Note that the Y is capitalised:
$ confirm_yes "Show dangerous command" && echo "rm *"
Show dangerous command [Y/n]?
rm *
Above, I just pressed enter, so the command ran.
No default on enter - require y or n
$ get_yes_keypress "Here you cannot press enter. Do you like this"
Here you cannot press enter. Do you like this [y/n]? k
Here you cannot press enter. Do you like this [y/n]?
Here you cannot press enter. Do you like this [y/n]? n
$ echo $?
1
Here, 1 or false was returned. Note no capitalisation in [y/n]?
Code
# Read a single char from /dev/tty, prompting with "$*"
# Note: pressing enter will return a null string. Perhaps a version terminated with X and then remove it in caller?
# See https://unix.stackexchange.com/a/367880/143394 for dealing with multi-byte, etc.
function get_keypress {
local REPLY IFS=
>/dev/tty printf '%s' "$*"
[[ $ZSH_VERSION ]] && read -rk1 # Use -u0 to read from STDIN
# See https://unix.stackexchange.com/q/383197/143394 regarding '\n' -> ''
[[ $BASH_VERSION ]] && </dev/tty read -rn1
printf '%s' "$REPLY"
}
# Get a y/n from the user, return yes=0, no=1 enter=$2
# Prompt using $1.
# If set, return $2 on pressing enter, useful for cancel or defualting
function get_yes_keypress {
local prompt="${1:-Are you sure} [y/n]? "
local enter_return=$2
local REPLY
# [[ ! $prompt ]] && prompt="[y/n]? "
while REPLY=$(get_keypress "$prompt"); do
[[ $REPLY ]] && printf '\n' # $REPLY blank if user presses enter
case "$REPLY" in
Y|y) return 0;;
N|n) return 1;;
'') [[ $enter_return ]] && return "$enter_return"
esac
done
}
# Credit: http://unix.stackexchange.com/a/14444/143394
# Prompt to confirm, defaulting to NO on <enter>
# Usage: confirm "Dangerous. Are you sure?" && rm *
function confirm {
local prompt="${*:-Are you sure} [y/N]? "
get_yes_keypress "$prompt" 1
}
# Prompt to confirm, defaulting to YES on <enter>
function confirm_yes {
local prompt="${*:-Are you sure} [Y/n]? "
get_yes_keypress "$prompt" 0
}
Well, here's my version of confirm, modified from James' one:
function confirm() {
local response msg="${1:-Are you sure} (y/[n])? "; shift
read -r $* -p "$msg" response || echo
case "$response" in
[yY][eE][sS]|[yY]) return 0 ;;
*) return 1 ;;
esac
}
These changes are:
use local to prevent variable names from colliding
read use $2 $3 ... to control its action, so you may use -n and -t
if read exits unsuccessfully, echo a line feed for beauty
my Git on Windows only has bash-3.1 and has no true or false, so use return instead. Of course, this is also compatible with bash-4.4 (the current one in Git for Windows).
use IPython-style "(y/[n])" to clearly indicate that "n" is the default.
This version allows you to have more than one case y or Y, n or N
Optionally: Repeat the question until an approve question is provided
Optionally: Ignore any other answer
Optionally: Exit the terminal if you want
confirm() {
echo -n "Continue? y or n? "
read REPLY
case $REPLY in
[Yy]) echo 'yup y' ;; # you can change what you do here for instance
[Nn]) break ;; # exit case statement gracefully
# Here are a few optional options to choose between
# Any other answer:
# 1. Repeat the question
*) confirm ;;
# 2. ignore
# *) ;;
# 3. Exit terminal
# *) exit ;;
esac
# REPLY=''
}
Notice this too: On the last line of this function clear the REPLY variable. Otherwise if you echo $REPLY you will see it is still set until you open or close your terminal or set it again.
Late to the game, but I created yet another variant of the confirm functions of previous answers:
confirm ()
{
read -r -p "$(echo $#) ? [y/N] " YESNO
if [ "$YESNO" != "y" ]; then
echo >&2 "Aborting"
exit 1
fi
CMD="$1"
shift
while [ -n "$1" ]; do
echo -en "$1\0"
shift
done | xargs -0 "$CMD" || exit $?
}
To use it:
confirm your_command
Features:
prints your command as part of the prompt
passes arguments through using the NULL delimiter
preserves your command's exit state
Bugs:
echo -en works with bash but might fail in your shell
might fail if arguments interfere with echo or xargs
a zillion other bugs because shell scripting is hard
Try,
#!/bin/bash
pause ()
{
REPLY=Y
while [ "$REPLY" == "Y" ] || [ "$REPLY" != "y" ]
do
echo -e "\t\tPress 'y' to continue\t\t\tPress 'n' to quit"
read -n1 -s
case "$REPLY" in
"n") exit ;;
"N") echo "case sensitive!!" ;;
"y") clear ;;
"Y") echo "case sensitive!!" ;;
* ) echo "$REPLY is Invalid Option" ;;
esac
done
}
pause
echo "Hi"
This isn't exactly an "asking for yes or no" but just a hack: alias the hg push ... not to hgpushrepo but to hgpushrepoconfirmedpush and by the time I can spell out the whole thing, the left brain has made a logical choice.
Not the same, but idea that works anyway.
#!/bin/bash
i='y'
while [ ${i:0:1} != n ]
do
# Command(s)
read -p " Again? Y/n " i
[[ ${#i} -eq 0 ]] && i='y'
done
Output:
Again? Y/n N
Again? Y/n Anything
Again? Y/n 7
Again? Y/n &
Again? Y/n nsijf
$
Now only checks 1st character of $i read.
Below code is combining two things
shopt -s nocasematch that will take care of case insensitive
and if condition that will accept both the input either you pass yes,Yes,YES,y.
shopt -s nocasematch
if [[ sed-4.2.2.$LINE =~ (yes|y)$ ]]
then exit 0
fi
Here is my solution that using localised regex. So in german also "j" for "Ja" would be interpreted as yes.
First argument is the question, if the second argument is "y" than yes would be the default answer otherwise no would be the default answer. The return value is 0 if the answer was "yes" and 1 if the answer was "no".
function shure(){
if [ $# -gt 1 ] && [[ "$2" =~ ^[yY]*$ ]] ; then
arg="[Y/n]"
reg=$(locale noexpr)
default=(0 1)
else
arg="[y/N]"
reg=$(locale yesexpr)
default=(1 0)
fi
read -p "$1 ${arg}? : " answer
[[ "$answer" =~ $reg ]] && return ${default[1]} || return ${default[0]}
}
Here is a basic usage
# basic example default is no
shure "question message" && echo "answer yes" || echo "answer no"
# print "question message [y/N]? : "
# basic example default set to yes
shure "question message" y && echo "answer yes" || echo "answer no"
# print "question message [Y/n]? : "
I know this is an old question but this might help someone, it hasn't been addressed here.
I have been asked how to use rm -i in a script which is receiving input from a file. As file input to a script is normally received from STDIN we need to change it, so that only the response to the rm command is received from STDIN. Here's the solution:
#!/bin/bash
while read -u 3 line
do
echo -n "Remove file $line?"
read -u 1 -n 1 key
[[ $key = "y" ]] && rm "$line"
echo
done 3<filelist
If ANY key other than the "y" key (lower case only) is pressed, the file will not be deleted. It is not necessary to press return after the key (hence the echo command to send a new line to the display).
Note that the POSIX bash "read" command does not support the -u switch so a workaround would need to be sought.
Yes default base on Dennis Williamson answer
#!/bin/bash
confirm() {
# call with a prompt string or use a default
read -r -p "${1:-Are you sure?} [Y/n] " response
case "$response" in
#([nN])*([oO]))
false
;;
*)
true
;;
esac
}
I like to exit as soon as possible if the user isn't sure, and I like the code to be readable and short. Depending on whether you'd like the user to press Return after their answer or not,
With pressing Return,
read -p "Warning: something scary: Continue (Y/N)? " reply
[ $reply != 'Y' ] && [ $reply != 'y' ] && echo 'Aborting' && exit 1
echo 'Scary thing'
or if you prefer not to wait for the user to press Return,
read -n1 -p "Warning: something scary: Continue (Y/N)? " reply
echo ''
[ $reply != 'Y' ] && [ $reply != 'y' ] && echo 'Aborting' && exit 1
echo 'Scary thing'
The other answers have the background on that -n1 flag and other options for read. The echo '' in the 2nd variant is to make subsequent output appear on a new line since the user doesn't have to press Return, so no newline has been echoed to the terminal.
I'm trying to write a program where the program will ask you your name, confirm that you want this name, then check to see if you said yes or no. I have the "no" loop working, where it will ask for a name again, but I'm trying to a loop where if you type anything other than yes or no it will say "Please type yes or no." then ask if you want to confirm your name, then check the answer again. Heres what I have.
echo -e $WHITE"Name your$GREEN Hero$WHITE."
read HERO
clear
echo -e "Are you sure you want your$GREEN Hero$WHITE's name to be$GREEN "$HERO"$WHITE? y/n"
read ANSWER1
while [ $ANSWER1 = "no" ]; do
#
#
#
clear
echo -e $WHITE"Name your$GREEN Hero$WHITE."
read HERO
clear
echo -e "Are you sure you want your$GREEN Hero$WHITE's name to be$GREEN "$HERO"$WHITE? y/n"
read ANSWER1
done
while [ $ANSWER1 != "yes" ] || [ $ANSWER1 != "no" ]; do
#
#
#
clear
echo -e $WHITE"Please type yes or no."
sleep 1.5
clear
echo -e $WHITE"Are you sure you want your$GREEN Hero$WHITE's name to be$GREEN "$HERO"$WHITE?"
read ANSWER1
clear
done
clear
echo -e -n $WHITE"Loading"
sleep 1.5
echo -e -n "."
sleep 1.5
echo -e -n "."
sleep 1.5
echo -e -n "."
sleep 1.5
clear
echo -e "Done."
If I go through the "Please type yes or no." it will freeze at the sleep and not clear, therefore not displaying the echo and continuing the loop. Any help or suggestions would be greatly appreciated!
Here's the problem:
while [ $ANSWER1 != "yes" ] || [ $ANSWER1 != "no" ]; do
Every possible answer is different to at least one of them. There's no string that's equal to yes and no at the same time. You need && instead of ||.
An easier way to write a loop to get user's input is the select command:
while true; do
read -p "${white}Name your ${green}Hero$white: " hero
echo "Are you sure you want your ${green}Hero$white's name to be $green\"$hero\"$white? "
select ans in Yes No; do
case $ans in
Yes) break 2 ;; # break out of both select and while loops
No) break ;; # only break out of select loop
esac
done
done
echo "Your ${green}Hero$white's name is $green\"$hero\"$white."
I recently created a different thread with an issue concerning a for loop in a bash script I was writing for my GCSE coursework. I have another issue with the same bash script (however it has evolved a fair bit since last time).
Here is the code:
#!/bin/bash
# A script that creates users.
uerror='^[0-9]+$'
echo "This is a script to create new users on this system."
echo "How many users do you want to add? (in integer numbers)"
read am
echo " "
if [[ $am =~ $uerror ]] ; then
echo "ERROR: Please use integer numbers."
echo "Please re-enter the amount."
read am ;
else
echo " "
for i in $(seq "$am")
do
echo "Enter a username below:"
read usern
sudo useradd $usern
sudo passwd $usern
echo " "
echo "User $i '$usern' added."
echo " "
echo "What group do you want to add $usern to?"
read group
sudo usermod $usern -aG $group
echo "$usern added to $group"
echo " "
echo "-------------------"
echo " "
done
fi
The issue is in the if statement. It's purpose is to stop users entering anything other than an integer number. But for some reason, I don't seem to be able to capture the input from the read am part. Instead the script skips straight onto the for loop where the $(seq "$am") obviously will have issues comprehending an input that is not a number.
The output from this error is as follows.
seq: invalid floating point argument
However, I don't think this is relevant because as far as I can tell, the issue is with the if / else statement.
If anyone could point me in the right direction of what I need to do to fix this, I would be greatly appreciative.
I'd also like to iterate that I am still learning how to write bash scripts (and not in a particularly organised manner) so I've probably made a very simple mistake. Apologies for that.
Thanks,
Callum.
EDIT: I mistyped an echo message, I've now changed that so it actually makes sense.
If you want to read in a number and make sure it is a number use a while loop:
while read -p 'type a number:' n ; do
# Exit the loop if the input is a number
[[ "$n" =~ ^[0-9]+$ ]] && break
echo "This was not a number! Don't trick me!"
done
# Now can use `seq`
seq "$n"
The if statement in your example would do the completely the wrong thing. It checks if the input is a number and in that case asks for the input again and exits the script. If you don't type a number, it uses the (wrong) input in the else branch.
Replace your whole file with this:
#!/bin/bash
# A script that creates users.
uerror='^[0-9]+$'
echo "This is a script to create new users on this system."
echo "How many users do you want to add? (in integer numbers)"
read am
echo " "
while true; do
if [[ $am =~ $uerror ]] ; then
break;
else
echo "Must be integer"
echo "Please re-enter: "
read am ;
fi
done
for i in $(seq "$am")
do
echo "Enter a username below:"
read usern
sudo useradd $usern
sudo passwd $usern
echo " "
echo "User $i '$usern' added."
echo " "
echo "What group do you want to add $usern to?"
read group
sudo usermod $usern -aG $group
echo "$usern added to $group"
echo " "
echo "-------------------"
echo " "
done
Sorry for the trouble.. here is the code what works for a single server. I need help to loop it to multiple servers. Thanks in advance, Please help me out .
I need to know information of multiple servers like their:
Operating system info
Hostname and dns info
Network info
Who is online
Last logged in users and so on
logic is to pass the server names from a text file and display the same info for all the server in the file and write output to other file
Below are the different fucntions which fetch the details of a server. The same should be iterated for multiple servers..
#!/bin/bash
# grabsysinfo.sh - A simple menu driven shell script to to get information about your
# Linux server / desktop.
# Define variables
LSB=/usr/bin/lsb_release
# Purpose: Display pause prompt
# $1-> Message (optional)
function pause(){
local message="$#"
[ -z $message ] && message="Press [Enter] key to continue..."
read -p "$message" readEnterKey
}
# Purpose - Display a menu on screen
function show_menu(){
date
echo "---------------------------"
echo " Main Menu"
echo "---------------------------"
echo "1. Operating system info"
echo "2. Hostname and dns info"
echo "3. Network info"
echo "4. Who is online"
echo "5. Last logged in users"
echo "6. Free and used memory info"
echo "7. exit"
}
# Purpose - Display header message
# $1 - message
function write_header(){
local h="$#"
echo "---------------------------------------------------------------"
echo " ${h}"
echo "---------------------------------------------------------------"
}
# Purpose - Get info about your operating system
function os_info(){
write_header " System information "
echo "Operating system : $(uname)"
[ -x $LSB ] && $LSB -a || echo "$LSB command is not insalled (set \$LSB variable)"
#pause "Press [Enter] key to continue..."
pause
}
# Purpose - Get info about host such as dns, IP, and hostname
local dnsips=$(sed -e '/^$/d' /etc/resolv.conf | awk '{if (tolower($1)=="nameserver") print $2}')
write_header " Hostname and DNS information "
echo "Hostname : $(hostname -s)"
echo "DNS domain : $(hostname -d)"
echo "Fully qualified domain name : $(hostname -f)"
echo "Network address (IP) : $(hostname -i)"
echo "DNS name servers (DNS IP) : ${dnsips}"
pause
}
# Purpose - Network inferface and routing info
function net_info(){
devices=$(netstat -i | cut -d" " -f1 | egrep -v "^Kernel|Iface|lo")
write_header " Network information "
echo "Total network interfaces found : $(wc -w <<<${devices})"
echo "*** IP Addresses Information ***"
ip -4 address show
echo "***********************"
echo "*** Network routing ***"
echo "***********************"
netstat -nr
echo "**************************************"
echo "*** Interface traffic information ***"
echo "**************************************"
netstat -i
pause
}
# Purpose - Display a list of users currently logged on
# display a list of receltly loggged in users
function user_info(){
local cmd="$1"
case "$cmd" in
who) write_header " Who is online "; who -H; pause ;;
last) write_header " List of last logged in users "; last ; pause ;;
esac
}
# Purpose - Display used and free memory info
function mem_info(){
write_header " Free and used memory "
free -m
echo "*********************************"
echo "*** Virtual memory statistics ***"
echo "*********************************"
vmstat
echo "***********************************"
echo "*** Top 5 memory eating process ***"
echo "***********************************"
ps auxf | sort -nr -k 4 | head -5
pause
}
# Purpose - Get input via the keyboard and make a decision using case..esac
function read_input(){
local c
read -p "Enter your choice [ 1 - 7 ] " c
case $c in
1) os_info ;;
2) host_info ;;
3) net_info ;;
4) user_info "who" ;;
5) user_info "last" ;;
6) mem_info ;;
7) echo "Bye!"; exit 0 ;;
*)
echo "Please select between 1 to 7 choice only."
pause
esac
}
# ignore CTRL+C, CTRL+Z and quit singles using the trap
trap '' SIGINT SIGQUIT SIGTSTP
First you need Key-Based SSH login to your remote servers (https://help.ubuntu.com/community/SSH/OpenSSH/Keys#Key-Based_SSH_Logins)
After that you use a loop like this:
function read_input(){
read -p "Enter your choice [ 1 - 7 ] " c
for server in $(cat your_server_file);
do
case $c in
1) os_info $server;;
2) host_info $server;;
3) net_info $server;;
4) user_info "who" $server;;
5) user_info "last" $server;;
6) mem_info $server;;
7) echo "Bye!"; exit 0 ;;
*)
echo "Please select between 1 to 7 choice only."
pause
esac
done
}
And in example your mem_info function
function mem_info(){
server=$1
write_header " Free and used memory "
ssh ssh_remote_user#server free -m
echo "*********************************"
echo "*** Virtual memory statistics ***"
echo "*********************************"
ssh ssh_remote_user#server vmstat
echo "***********************************"
echo "*** Top 5 memory eating process ***"
echo "***********************************"
ssh ssh_remote_user#server ps auxf | sort -nr -k 4 | head -5
pause
}
UPDATE
If you use sshpass you have to change a little bit.
Your your_server_file should look like this:
user1#password1|user1#server1
user2#password2|user2#server2
...
Your main function
function read_input(){
read -p "Enter your choice [ 1 - 7 ] " c
for line in $(cat your_server_file);
do
user_pass=$(echo $line | sed -e 's/\(.*\)|\(.*\)/\1/')
server=$(echo $line | sed -e 's/\(.*\)|\(.*\)/\2/')
case $c in
1) os_info $server $user;;
2) host_info $server $user;;
3) net_info $server $user;;
4) user_info "who" $server $user;;
5) user_info "last" $server $user;;
6) mem_info $server $user;;
7) echo "Bye!"; exit 0 ;;
*)
echo "Please select between 1 to 7 choice only."
pause
esac
done
}
And the mem_info function
function mem_info(){
server=$1
user_pass=$2
write_header " Free and used memory "
sshpass -p $user_pass ssh $server free -m
echo "*********************************"
echo "*** Virtual memory statistics ***"
echo "*********************************"
sshpass -p $user_pass ssh $server vmstat
echo "***********************************"
echo "*** Top 5 memory eating process ***"
echo "***********************************"
sshpass -p $user_pass ssh $server ps auxf | sort -nr -k 4 | head -5
pause
}
I did not quote anything. Please take care about special characters