Continue function after CASE statement - linux

I have this function
function doit {
echo " Do you want to continue? {y/n} "
case $opt in
y) ??????
n) exit ;;
esac
echo " 32b or 64b? {32/64} "
case $opt in
32) do32 ;;
64) do64 ;;
esac
}
How do I make this work ? I need to keep moving forward in the same function after the YES is chosen.

This is extremely unclear, but I guess you mean
doit () {
read -p " Do you want to continue? {y/n} " opt
case $opt in
y) ;;
n) return 1 ;;
esac
read -p " 32b or 64b? {32/64} " opt
case $opt in
32) do32 ;;
64) do64 ;;
esac
}
The option to do nothing at all in the y case seems to be the answer to your question. But notice also the use of return rather than exit to leave the function, the absence of a function keyword in the function declaration (this is only a matter of preference really; but I see no advantage of the Bash-only syntax variant), and the use of read to read input (I guess that's what you wanted here?). The return argument 1 signals failure to the caller, so you can say e.g.
doit || echo "$0: doit failed or aborted" >&2
Strictly speaking, the first case only needs an n branch; you'll notice that the code simply falls through if the answer is not either n or y, and this behavior is actually suitable for the y case too. Where this is not the case, a final *) case can be used to handle all the otherwise unhandled values.

I wouldn't use a case statement when you only care about one of the branches:
function doit {
read -p " Do you want to continue? {y/n} " ans
[[ $ans == [nN]* ]] && return 1
PS3=" 32b or 64b? "
select size in 32 64; do
case $size in
32|64) break ;;
esac
done
do${size}
}

Related

how to call a function with 2 arguments which under the option of "getopts"

New in Linux bash script.
Here I tried to create some files with getopts. For example I'd like to create 3 files called xyzfile, in command line ./createfiles -n xyzfile 3should be given (2 arguments after the option -n). The result should be 3 files with the names xyzfile_1, xyzfile_2 and xyzfile_3.
I tried to put my createfile() function outside the while-loop and as well as inside the while-loop. But the option -n doesn't work.
I also tried to create another function called foo() with included the function createfile(), but still something wrong there.
I have no idea anymore what I can do. Hope I can get some advices from you guys. Thank you very much!
#!/bin/bash
while getopts :n:bc opt; do
case $opt in
n) echo test 3333333
createfile() {
echo "$OPTARG"
sum=$2
for((i=1;i<=sum;i++))
do
touch "$OPTARG_${i}"
done
}
createfile $OPTARG ${2};;
b) echo "test 1111111";;
c) echo "test 2222222";;
*) echo error!;;
esac
done
Use a separate option for the count, and create your files after the option processing.
Something like:
while getopts "n:c:" opt; do
case $opt in
n) name="$OPTARG";;
c) count=$OPTARG;;
# other options...
esac
done
shift $((OPTIND -1))
while (( count > 0 )); do
touch "${name}_$count"
(( count-- ))
# ...
done
getopts supports only options without, or with one argument. So you'll have to decide on which way you want your script to work. You have multiple options:
add a new option -m or similar to pass the maximum number of files you want to create: createfile -n xyzfile -m 3
you can also use the arguments that are not passed as an option, if you do your parsing well then createfile 3 -n xyzfile or createfile -n xyzfile 3 would mean the same. In my scripts I often use such positional argument if there is one option that the user always needs to pass.
You might even consider changing your way of calling the script to createfile xyzfile -n 3 or even createfile xyzfile where the name is a positional argument and the number of files optional (choose a logical default value, probably 1)...
Parse the options first, then use the values you discover. An option can take only a single argument, so -n only gets the first one (I'll keep that as the file-name stem here). The count will be an ordinary positional argument found after parsing the options.
while getopts :n:bc opt; do
case $opt in
n) stem=$OPTARG; shift 2;;
b) shift 1;;
c) shift 1;;
*) shift 1; echo error ;;
esac
done
count=${1?No count given}
createfile () {
for ((i=$1; i<=$2; i++)); do
touch "${1}_${i}"
done
}
createfile "$stem" "$count"

Breaking out of nested function loops in Bash

I am using a nested function to partition and making the filesystem for drives attached to a new Linux box.
I am having a strange issue trying to break out of all loops.
I am keeping track of the nested loop index and using "break n".
When the user replies "n" to the question "Do you have any additional drives to partition?" i expect to break out of all nested loops and continue with the script, but what happens is that the question gets asked again.
Can you help me figure this out?
INIT_STARTED=0
chooseDisks()
{
INIT_STARTED=$((INIT_STARTED+1))
# Choosing which drive to work on
read -p "Please type the name of the disk you want to partition: " DISK
while true; do
read -p "Are you sure you want to continue ? y (partition)/n (choose another drive) /x (continue) " ynx
case $ynx in
[Yy]* )
containsElement "$DISK"
if [ $? == 1 ]; then
initializeDisk $DISK
# remove element from found disk to prevent trying to partition it again.
delete=($DISK)
FOUNDDISKS=( "${FOUNDDISKS[#]/$delete}" )
else
echo "${red}$DISK is not a valid choice, please select a valid disk.${reset}"
chooseDisks
fi
break;;
[Nn]* )
chooseDisks
break $((INIT_STARTED));;
[Xx]* )
return
break;;
* ) echo "Please answer y or n. x to continue the script.";;
esac
done
# Any additional disks to partition?
while true; do
read -p "Do you have any additional drives to partition ? y/n " yn
case $yn in
[Yy]* )
#chooseDisks $FOUNDDISKS
chooseDisks
break $((INIT_STARTED));;
[Nn]* )
return
break $((INIT_STARTED));;
* ) echo "Please answer y or n";;
esac
done
}
I expect this:
break $((INIT_STARTED));;
to end the nth loop and exiting the function.
Don't play with nested logic break, just use some variable like $userStop and instead of while true; do put
userStop = false
while[!${userStop}]
do
#...
# replace break $((INIT_STARTED));; by
# userStop = true
I ended up changing the code to avoid breaking within a loop.
Thanks guys for directing me the right way.
David
i expect to break out of all nested loops and continue with the script
You can run the function in a subshell and use exit.
chooseDisks()
{
if [ "$1" -eq 0 ]; then
echo "The user entered it all!"
exit 0
fi
echo "The user is still entering... $1"
( chooseDisks $(($1 - 1)) )
}
# Imagine the user 5 times enters something
( chooseDisks 5 )
But the best would be to refactor your code to just have a big while true; do loop in the beginning. There is no need to make this function recursive.

Parsing long and short args in ksh using loop

I am trying to parse arguments in ksh. Can't do getopt for the same as in short options I have two/three characters. Currently I am using for loop. Its stupid but am unable to find something better.
Question: How do I set option+value as one unit in order to parse?
Also if eval set -- $option will help me then how do I use it? echo on option does not show the expected "--" at the end. Am I assuming something wrong?
I am thinking of using a variable to keep track of when an option is found but this method seems too confusing and unnecessary.
Thanks for your time and help.
Update 1:
Adding code as pointed out. Thanks to markp, Andre Gelinas and random down-voter in making this question better. Trying to execute the script as given in line 2 and 3 of code - or any other combination of short and long options passed together.
#!/bin/ksh
# bash script1.sh --one 123 --two 234 --three "some string"
# bash script1.sh -o 123 -t 234 -th "some string"
# the following creates problems for short options.
#options=$(getopt -o o:t:th: -l one:two:three: "--" "$#")
#Since the below `eval set -- "$options"` did not append "--" at the end
#eval set -- "$options"
for i in $#; do
options="$options $i"
done
options="$options --"
# TODO capture args into variables
Attempted code below TODO until now:
for i in $options; do
echo $i
done
Will be capturing the args using:
while true; do
case $1 in
--one|-o) shift; ONE=$1
;;
--two|-t) shift; TWO=$1
;;
--three|-th) shift; THREE=$1
;;
--) shift; break
;;
esac
done
Try something like this :
#!/bin/ksh
#Default value
ONE=123
TWO=456
# getopts configuration
USAGE="[-author?Andre Gelinas <andre.gelinas#foo.bar>]"
USAGE+="[-copyright?2018]"
USAGE+="[+NAME?TestGetOpts.sh]"
USAGE+="[+DESCRIPTION?Try out for GetOps]"
USAGE+="[o:one]#[one:=$ONE?First.]"
USAGE+="[s:second]#[second:=$TWO?Second.]"
USAGE+="[t:three]:[three?Third.]"
USAGE+=$'[+SEE ALSO?\aman\a(1), \aGetOpts\a(1)]'
while getopts "$USAGE" optchar ; do
case $optchar in
o) ONE=$OPTARG ;;
s) TWO=$OPTARG ;;
t) THREE=$OPTARG ;;
esac
done
print "ONE = "$ONE
print "TWO = "$TWO
print "THREE = "$THREE
You can use either --one or -o. Using --man or --help are also working. Also -o and -s are numeric only, but -t will take anything. Hope this help.

Variable While Loop

I would like to know how to include -, *, and ,/, in the following while loop in addition to the + I have already included. If the user enters something other than +, -, * or / I want the invalid input message to print. However, so far I have only worked out how to include one of the arguments in the code, in this case the +. How do I include the other 3 arguments in the same bit of code? I am a noobie I admit, and I don't currently have the vocabulary to search an answer specific to my needs so thought my best best was writing out the issue.
Any help appreciated. Thanks
echo "Please enter an operation of arithmetic. Press either +, -, * or /"
read operation
while [ $operation != "+" ]; do
echo "sorry, that is an invalid input- re-enter operation of arithmatic"
read operation
You can use that in a while loop like this:
while read -p "Please enter an operation of arithmetic. Press either +, -, * or /: " op &&
[[ $op != [-+/*] ]]; do
echo "sorry, that is an invalid input- re-enter operation of arithmatic"
done
You probably want select here:
PS3="Please enter an operation of arithmetic: "
select op in + - / '*'; do
case $op in
-) echo subtract something ; break ;;
+) echo add something ; break ;;
/) echo divide something ; break ;;
\*) echo multiply something ; break ;;
esac
done

If string contains in case statement

I'm looking to provide a case statement based on whether a substring is within a filename.
Example Input
mysql_dumps/tpmysqldump-tps_dev_russell_development-information_schema-2014-03-26.sql
Code
case $DUMPFILE in
*"tpdata"*)
database="tpdata";;
*"tpmrbs"*)
database="tpmrbs";;
*"information_schema"*)
database="information_schema";;
*"performance_schema"*)
database="performance_schema";;
*)
echo "INVALID FILE";;
esac
How do you initialize $DUMPFILE? If I run the following, the output is information_schema, which is what I expected...
#!/bin/bash
DUMPFILE=mysql_dumps/tpmysqldump-tps_dev_russell_development-information_schema-2014-03-26.sql
case $DUMPFILE in
*"tpdata"*)
database="tpdata";;
*"tpmrbs"*)
database="tpmrbs";;
*"information_schema"*)
database="information_schema";;
*"performance_schema"*)
database="performance_schema";;
*)
echo "INVALID FILE";;
esac
echo $database

Resources