How do i jump back to the previous read if left empty - bash

Default_Dir=/export/home/cwatts/test
Default_Log=DB.Audit
echo "Please, enter your Fullname [ENTER]:"
read fname
if [ -z "$fname" ]; then
echo "Please enter a value!"
exit 0
else
echo "Please, enter the Database name [ENTER]:"
read dbname
if [ -z "$dbname" ]; then
echo "Please enter a value!"
else
echo "Please, enter a brief Description [ENTER]:"
read desc
if [ -z "$desc" ]; then
echo "Please enter a value!"
fi
fi
fi
if [ ! -d $Default_Dir ]; then
echo "directory doesn't exit, it will be created"
mkdir $Default_Dir
fi
echo `date -u` $dbname $fname $desc >> $Default_Dir/$Default_Log
exit

You can do something like this:
while [ -z "${value-}" ]
do
echo "Please, enter your Fullname [ENTER]:"
read value
done

Expanding somewhat on l0b0's answer and refactoring for legibility and idiomatic expression:
nonempty () {
test -n "$1" && return 0
echo "Please enter a value" >&2
return 1
}
while true; do
read -p "Please, enter your Fullname [ENTER]: " fname
nonempty "$fname" || continue
read -p "Please, enter the Database name [ENTER]: " dbname
nonempty "$dbname" || continue
read -p "Please, enter a brief Description [ENTER]:" desc
nonempty "$desc" || continue
break
done
date -u +"%c $dbname $fname $desc" >> $Default_Dir/$Default_Log
(The hack to put the string you want to echo in the format string of date will break if any of the values could contain a percent sign.)
If you are okay with the slightly dubious practice of having a function define global variables for you, the code duplication can still be reduced significantly.
accept () {
read -p "$2 [ENTER]: " "$1"
test -n "${!1}" && return 0
echo "Please enter a value" >&2
return 1
}
while true; do
accept fname "Please, enter your Fullname" || continue
accept dbname "Please, enter the Database name" || continue
accept desc "Please, enter a brief Description" || continue
break
done
The indirect variable reference ${!var} is a Bashism, and not portable to other shells.

Related

How to make while loop return to start and how to add a loop within a loop

I have made a script for an ordering system. I am currently stuck on trying to make my while loop work. For example at the end I would like the script to ask the user if they would like to place another order and if so it should loop back to the start. Additionally, if invalid input is entered it should loop back to where the input is asked for. for example at I attempted to do this between line 9 and 23 for but was not able to get the while loop to work here.
#!/bin/bash
clear
echo "orderBeds"
while :
do
read -p "Please enter your choice (Quit/Order) " order
if [ $order == "order" ] || [ $order == "Order" ]
then
read -p "Please enter your name " name
elif [ $order == "quit" ] || [ $order == "Quit" ]
then
echo "-----Thanks for your purchase! -----"
exit
else
[ $order != "order" ] || [ $order != "Order" ] || [ $order != "quit" ] || [ $order != "Quit" ]
echo "Invaild input, Please use a vauld input"
fi
read -p "Please enter your telephone number? " telephone
if ! [[ "$telephone" =~ ^[0-9]+$ ]]
then
echo "Sorry integers only"
else
echo $telephone
fi
read -p "what kind of bed would you like? (Single/Double/Kingsize)" bed
if [ $bed != "Single" ] || [ $bed != "Double" ] || [ $bed != "Kingsize" ]
echo $bed
then
echo "Please enter a vaild bed Type (Single/Double/Kingsize)"
else
return
fi
read -p "Would you like to place another order? (Quit/Order)" order
if [ $order == "order" ] || [ $order == "Order" ]
then
read -p "Please enter your name " name
elif [ $order == "quit" ] || [ $order == "Quit" ]
then
echo "-----Thanks for your purchase! -----"
exit
fi
done
Fixed your script to break out of loop when entry is valid.
#!/usr/bin/env bash
clear
echo "orderBeds"
read -r -p "Please enter your choice (Quit/Order) " order
while :; do
while ! [[ $order =~ ^(([Oo]rder)|([Qq]uit))$ ]]; do
echo "Invaild input, Please use a vauld input" >&2
read -r -p "Please enter Quit or Order) " order
done
if [[ -n "${BASH_REMATCH[2]}" ]]; then
read -r -p "Please enter your name " name
else
echo "-----Thanks for your purchase! -----"
exit
fi
echo "$name"
while :; do
read -r -p "Please enter your telephone number? " telephone
[[ $telephone =~ ^[[:digit:]]+$ ]] && break
echo "Sorry digits only" >&2
done
echo "$telephone"
while :; do
read -r -p "what kind of bed would you like? (Single/Double/Kingsize)" bed
[[ $bed =~ ^(Single|Double|Kingsize)$ ]] && break
echo "Please enter a valid bed Type (Single/Double/Kingsize)" >&2
done
echo "$bed"
read -r -p "Would you like to place another order? (Quit/Order)" order
done

assign number value to alphabet in shell/bash

I have a script that prompts for the user to enter a 3 letter code. I need to convert that code to a number that corresponds to a=01, b=02....etc for the first two letters of that code.
For example the user enters ABC for $SITECODE I need to take the A&B and convert it to 0102 and store it to a new variable.
#!/bin/bash
# enable logging
exec 3>&1 4>&2
trap 'exec 2>&4 1>&3' 0 1 2 3
exec 1>/var/log/ULFirstBoot.log 2>&1
###################################### global variables ######################################################
# top level domain
tld="somedomain.com"
# grabs the serial number for ComputerName
serial=`/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/Serial\ Number\ \(system\)/ {print $NF}'`
# Cocoadialog location
CD="/Users/Shared/cocoaDialog.app/Contents/MacOS/cocoaDialog"
################################################### Begin Define Functions ####################################################
userinput () # Function will promt for Username,SItecode, and Region using Cocoadialog
{
# Prompt for username
rv=($($CD inputbox --title "User Name" --no-newline --informative-text "Please Enter the Users Employee ID" --icon "user" --button1 "NEXT" --button2 "Cancel"))
USERNAME=${rv[1]}
if [ "$rv" == "1" ]; then
echo "`date` User clicked Next"
echo "`date` Username set to ${USERNAME}"
elif [ "$rv" == "2" ]; then
echo "`date` User Canceled"
exit
fi
# Dialog to enter the User name and the create $SITECODE variable
rv=($($CD inputbox --title "SiteCode" --no-newline --informative-text "Enter Site Code" --icon "globe" --button1 "NEXT" --button2 "Cancel"))
SITECODE=${rv[1]} #truncate leading 1 from username input
if [ "$rv" == "1" ]; then
echo "`date` User clicked Next"
echo "`date` Sitecode set to ${SITECODE}"
elif [ "$rv" == "2" ]; then
echo "`date` User Canceled"
exit
fi
# Dialog to enter the Password and the create $REGION variable
rv=($($CD dropdown --title "REGION" --text "Choose Region" --no-newline --icon "globe" --items NA EULA AP --button1 "OK" --button2 "Cancel"))
item=${rv[1]}
if [[ "$rv" == "1" ]]
then echo "`date` User clicked OK"
elif [[ "$rv" == "2" ]]
then echo "`date` User Canceled"
exit
fi
if [ "$item" == "0" ]; then
REGION="NA"
echo "`date` Region set to NA"
elif [ "$item" == "1" ]; then
REGION="EULA"
echo "`date` Region set to EULA"
elif [ "$item" == "2" ]; then
REGION="AP"
echo "`date` Region Set to AP"
fi
# Confirm that settings are correct
rv=($($CD msgbox --text "Verify settings are correct" --no-newline --informative-text "USER-$USERNAME REGION-$REGION, SITE CODE-$SITECODE" --button1 "Yes" --button2 "Cancel"))
if [[ "$rv" == "1" ]]
then echo "`date` User clicked OK"
elif [[ "$rv" == "2" ]]
then echo "`date` User Canceled"
exit
fi
}
# Sets computername based
setname ()
{
ComputerName=$SITECODE$serial
/usr/sbin/scutil --set ComputerName $SITECODE$serial
echo "`date` Computer Name Set to" $(/usr/sbin/scutil --get ComputerName)
/usr/sbin/scutil --set LocalHostName $SITECODE$serial
echo "`date` LocalHostname set to" $(/usr/sbin/scutil --get LocalHostName)
/usr/sbin/scutil --set HostName $SITECODE$serial.$tld
echo "`date` Hostname set to" $(/usr/sbin/scutil --get HostName)
}
adbind ()
{
OU="ou=Computers,ou=${SITECODE}Win7,ou=$REGION,dc=global,dc=ul,dc=com"
echo "`date` OU will be set to $OU"
dsconfigad -add "global.ul.com" -username "user" -password "password" -ou "$OU"
dsconfigad -mobile "enable" -mobileconfirm "disable" -groups "Domain Admins, ADMIN.UL.LAPTOPADMINS"
}
# Checks if machine is succesfully bound to AD before proceeding
adcheck ()
{
until [ "${check4AD}" = "Active Directory" ]; do
check4AD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`
sleep 5s
done
}
adduser () # creates mobile user account based on userinput function
{
# create mobile user account and home directory at /Users/username
/System/Library/CoreServices/ManagedClient.app/Contents/Resources/createmobileaccount -n $USERNAME -h /Users/$USERNAME
# Add newly created user to local admins group
dscl . -append /Groups/admin GroupMembership $USERNAME
# set login window to show username and password promts not a list of users
defaults write /Library/Preferences/com.apple.loginwindow SHOWFULLNAME 1
}
setADMPass ()
{
parsed1=${SITECODE:0:1}
parsed2=${SITECODE:1:1}
}
####################################### End define Functions ####################################################
############################################# Bgin Main Script #######################################################
userinput
setname
adbind
adcheck
adduser
echo $(dscl . -read /Groups/admin GroupMembership)
echo $(defaults 'read' /Library/Preferences/com.apple.loginwindow.plist SHOWFULLNAME)
# Reboot to apply changes
shutdown -r now "Rebooting to enable Mobile accounts"
Here's a funny way to do your encoding, abusing Bash's arithmetic:
string2code() {
# $1 is string to be converted
# return variable is string2code_ret
# $1 should consist of alphabetic ascii characters, otherwise return 1
# Each character is converted to its position in alphabet:
# a=01, b=02, ..., z=26
# case is ignored
local string=$1
[[ $string = +([[:ascii:]]) ]] || return 1
[[ $string = +([[:alpha:]]) ]] || return 1
string2code_ret=
while [[ $string ]]; do
printf -v string2code_ret '%s%02d' "$string2code_ret" "$((36#${string::1}-9))"
string=${string:1}
done
}
Try it:
$ string2code abc; echo "$string2code_ret"
010203
$ string2code ABC; echo "$string2code_ret"
010203
The magic happens here:
$((36#${string::1}-9))
The term 36# tells Bash that the following number is expressed in radix 36. In this case, Bash considers the characters 0, 1, ..., 9, a, b, c, ..., z (ignoring case). The term ${string:1} expands to the first character of string.
I found the answer thanks for all your help!
setADMPass ()
{
alower=abcdefghijklmnopqrstuvwxyz
site=$(echo $SITECODE | tr '[:upper:]' '[:lower:]')
parsed1=${site:0:1}
parsed2=${site:1:1}
tmp1=${alower%%$parsed1*} # Remove the search string and everything after it
ch1=$(( ${#tmp1} + 1 ))
tmp2=${alower%%$parsed2*} # Remove the search string and everything after it
ch2=$(( ${#tmp2} + 1 ))
if [[ $ch1 -lt 10 ]]; then
#statements
ch1=0$ch1
fi
if [[ $ch2 -lt 10 ]]; then
#statements
ch2=0$ch2
fi
passpre=$ch1$ch2
}
see if this helps! BASH 4+. If you find any issues, that'd be your homework.
#!/bin/bash
declare -A koba
i=1
for vi in {a..z};do koba=(["$vi"]="0${i}"); ((i++)); done
for vi in {A..Z};do koba=(["$vi"]="0${i}"); ((i++)); done
echo -en "\nEnter a word: "; read w; w="$( echo $w | sed "s/\(.\)/\1 /g" | cut -d' ' -f1,2)";
new_var="$(for ch in $w; do echo -n "${koba["${ch}"]}"; done)";
echo $new_var;

When running bash script that calls another script getting EOF error

The other script is just read statement that will be echo'ed into a file from this script
#!/usr/bin/bash
# createdb_wrapper.scr
# Log information about user of createdb.scr
Default_Dir=/export/home/cwatts/test
Default_Log=DB.Audit
while [ -z "${fname}" ]
do
echo "Please, enter your Fullname [ENTER]:"
read fname
done
Tried various ways to pull the information from the other script
dbname="./createDB.scr | awk '{print $1}'"
sh $dbname
while [ -z "${desc}" ]
do
echo "Please,enter a brief Description [ENTER]:
read desc
done
#Checks the directory exists, and creates if not
if [ ! -d $Default_Dir ] ;then
echo "directory doesn't exit, it will be created"
mkdir $Default_Dir
fi
echo `date -u` '|' $dbname '|' $fname '|' $desc >> $Default_Dir/$Default_Log
exit
You forgot the other quote:
echo "Please,enter a brief Description [ENTER]:
Should be
echo "Please,enter a brief Description [ENTER]:"
I also recommend this form:
#!/bin/bash
#
# createdb_wrapper.scr
# Log information about user of createdb.scr
#
DEFAULT_DIR='/export/home/cwatts/test'
DEFAULT_LOG='DB.Audit'
until read -p "Please, enter your Fullname [ENTER]: " FNAME && [[ -n $FNAME ]]; do
:
done
until read -p "Please,enter a brief Description [ENTER]: " DESC && [[ -n $DESC ]]; do
:
done
if [[ -d $DEFAULT_DIR ]]; then
echo "Directory does not exist. It will be created."
mkdir "$DEFAULT_DIR"
fi
echo "$(exec date -u) | $DBNAME | $FNAME | $DESC" >> "$DEFAULT_DIR/$DEFAULT_LOG"
Note: $DBNAME is not set.

Bash programming looping in if and case statement

Why is it the code on "if" statement will keep looping if null is input to "title" variable but for the case statement, my script will have error?
echo -n "Title :"
read title
if [ -z "$title" ]; then
echo "Please input a title"
while [[ -z "$title" ]] ; do
echo -n "Title: "
read title
done
fi
read author
case "$author" in
*[0-9,\""\!##$%\(\)]*) echo "Please enter a name" ;;
while *[1-9,\""\!##$%\(\)]*)"$author" ]] ; do
echo -n "author "
read author
esac
The line
while *[1-9,\""\!##$%\(\)]*)"$author" ]] ; do
wouldn't be allowed there even if there weren't a bunch a syntax errors in it. Try this idiom instead:
title=
while [ -z "$title ]
do
read -p "What is the title? " title
done
You have \"" and should be only \" . That's the syntax error
Also, you can't put a While as a case. Try this and add any cases you want
while [ -z $author ]; do
echo "Please enter an author: "
read author
case "$author" in
*[0-9,\"\!##$%\(\)]*) echo "First case - $author"
;;
esac
done

bash shell how to print line in file including pattern taken from user searching with data type for pattern

I want to take pattern from user and print line it includes (the whole record) in the terminal its a searching process but with data types id integer (pk) and name string and salary integer
More explanation: If I am searching with pattern 2 and its id I have to display only the id and not salary contains 2000 and that's the problem... I didn't face this problem with string names but its in id and salary.
The code is incorrectly formatted.
#! /bin/bash
#################taking tablename "database name"###############
echo "enter table name";
read tableName;
if [ -f ./tables/$tableName ];
then
#############check table exists######################
echo "File $tableName exists."
echo "1)search with the id";
echo "2)search with the name";
echo "3)search with the salary";
echo "enter your choice";
read input
echo "enter your pattern";
read pattern;
if [ $input -eq 1 ]
then
test= cut -d ',' -f1 ./tables/$tableName
if [[ ${#test[$pattern]} ]];
then
###############problem here################
fi
elif [ $input -eq 2 ]
then
grep $pattern ./tables/$tableName
elif [ $input -eq 3 ]
then
##########################problem here######################
else
echo "error in input";
fi
else
echo "table $tableName does not exist "
fi
##########################code ends#################
And the file has this records:
id:pk,name:str,salary:int,
2,tony,2000,
3,tony,2000,
4,sara,3000,
You could use a case to do different operations depending of the input choice. And in those cases, get the values from file.
echo "enter table name";
read tableName;
if [ ! -f ./tables/$tableName ]; then #Try to avoid looooong if/then blocks if you can handle the error right away
echo "table $tableName does not exist"
exit 1
fi
#############check table exists######################
echo "File $tableName exists."
echo "1)search with the id";
echo "2)search with the name";
echo "3)search with the salary";
echo "enter your choice";
read input
echo "enter your pattern";
read pattern;
entries=() #Initialize entries with an empty array
case $input in
1) #case by id
entries=($(grep -P "^${pattern}," "./tables/$tableName"))
;;
2) #case by name
entries=($(grep -P "^\d*,${pattern}," "./tables/$tableName"))
;;
3) #case by salary
entries=($(grep -P ",${pattern}$" "./tables/$tableName"))
;;
*) #choice not found
echo "error in input"
esac
if [[ "${#entries[#]}" = "0" ]]; then #entries array count is 0
echo "No entries found matching your pattern"
exit 1
fi
#To be noted that here, entries is useless if you just want to print the match
#(use grep directly and it will print the output).
#Thank's to Jonathan Leffler for this trick allowing to print a whole array in one line
printf "%s\n" "${entries[#]}"

Resources