Asking for user input in bash to set variable - bash

I want to have something which asks the user - "Which environment would you like to load?" - with valid response being either "production" or "development". If an answer is given which doesn't match either it re-asks the question. I want it to set the $production variable so I can run different parts of code later on. This is the closest I could do myself:
read -n1 -p "Which environment would you like to load? [production,development]" doit
case $doit in
production) echo $production=1 ;;
development) echo $production=0 ;;
*) echo ... ;;
esac
It doesn't seem to set the variable when I run it, so I don't know what I am doing wrong. Furthermore how do I make it to re-ask the question when a valid response isn't given?

If I understood you correctly, this is what you're looking for:
#!/bin/bash
while true; do
read -p "Which environment would you like to load? [production,development]" ANS
case $ANS in
'production')
production=1
break;;
'development')
production=0
break;;
*)
echo "Wrong answer, try again";;
esac
done
echo "Variable value:$production"
You start an infinite loop to ask for user input until it's valid.
If it's not valid it goes to default *) and you inform the user that it's wrong and then ask again, continuing in the loop.
When a match is found, you set your production variable and go out of the loop (with break). Now you code can continue with whatever you need, you got your variable setted up.

Problem is your use of read -n1 which will accept only one character in input.
Use:
read -r -p "Which environment would you like to load? [production,development]" doit
To set a default value while reading use -i 'defaultVal'option:
read -r -ei 'production' -p "Which environment would you like to load? [production,development]" doit

Related

Use a set of variables that start with the same string in bash

I know something like this is possible with DOS but I am not sure how to do it within bash.
I am writing a script that takes some configuration data: source, name, and destination. There will be a variable number of these in the configuration. I need to iterate over each set.
So, for example:
#!/bin/bash
FOLDER_1_SOURCE="/path/one"
FOLDER_1_NAME="one"
FOLDER_1_DESTINATION="one"
FOLDER_2_SOURCE="/path/two two"
FOLDER_2_NAME="two"
FOLDER_2_DESTINATION="here"
FOLDER_3_SOURCE="/something/random"
FOLDER_3_NAME="bravo"
FOLDER_3_DESTINATION="there"
FOLDER_..._SOURCE="/something/random"
FOLDER_..._NAME="bravo"
FOLDER_..._DESTINATION=""
FOLDER_X_SOURCE="/something/random"
FOLDER_X_NAME="bravo"
FOLDER_X_DESTINATION=""
Then I want to iterate over each set and get the SOURCE and NAME values for each set.
I am not stuck on this format. I just don't know how else to do this. The end goal is that I have 1 or more set of variables with source, name, and destination and then I need to iterate over them.
The answer to this type of question is nearly always "use arrays".
declare -a folder_source folder_name folder_dest
folder_source[1]="/path/one"
folder_name[1]="one"
folder_dest[1]="one"
folder_source[2]="/path/two two"
folder_name[2]="two"
folder_dest[2]="here"
folder_source[3]="/something/random"
folder_name[3]="bravo"
folder_dest[3]="there"
folder_source[4]="/something/random"
folder_name[4]="bravo"
folder_dest[4]=""
for((i=1; i<=${#folder_source[#]}; ++i)); do
echo "$i source:" "${folder_source[$i]}"
echo "$i name:" "${folder_name[$i]}"
echo "$i destination:" "${folder_dest[$i]}"
done
Demo: https://ideone.com/gZn0wH
Bash array indices are zero-based, but we just leave the zeroth slot unused here for convenience.
Tangentially, avoid upper case for your private variables.
AFIK bash does not have a facility to list all variables. A workaround - which also would mimic what is going on in DOS - is to use environment variables and restrict your search to those. In this case, you could do a
printenv|grep ^FOLDER||cut -d = -f 1
This is the same as doing in Windows CMD shell a
SET FOLDER

Bash - Read config files and make changes in this file

i have config file like this for example:
# Blah blah, this is sample config file blah blah
# Something more blah blah
value1=YES
value2=something
#value3=boom
# Blah blah
valueN=4145
And i want to make script to read and edit config files like this. I thinking about make a menu with groups of config options, then after write an option console output will be like this:
Group of funny options (pick option to change value):
1. value1=YES
2. value2=something
3. [disabled]value3=boom
After picking 1 for exaple i can change value1 from YES to NO or disable and activate other (hash unhash) plus adding new variables to the end of file. Then in the end save all changes in this config file. Any tips what i need to use? Actually trying with read line + awk to skip # lines (with space), but still i have problem to get all this variables and making changes in config file. I will be grateful for your help.
Edit.
while read line
do
echo $line | awk '$1' != "#" && / / { print $1 $3 }'
done < config.conf
Thinking about this for now to read informations what i want. Plus i'm gonna use something like this to change values:
sed -c -i "s/("one" *= *).*/\1$two/" config.conf
I have completly no idea how i can get this variables to my script and use it like i write before. Actually i search for any tips, not someone who write this script for me. I'm beginner at linux scripting :V
I would recommend to abstain from such an, seemingly generic configuration program, because the comments might contain important informations about the current value and will be outdated, if the values change, while the comments don't.
Second problem is, that I would expect, if activating an entry is possible, deactivating it should be possible too. So now you have 2 options what to do with each value.
Third problem: In most cases, guessing a type by the value might work. YES seems to be a boolean, 47 an int, foobar a name - or is it a file? - but often a wider type is possible too, so YES can be just a string or a file, 47.3 might be valid where 47 is or might be not and so on.
However, for experimenting and trying things out, select and grep might be a start:
select line in $(grep "=" sample.conf) "write" "abort"
do
case $line in
"write") echo write; break ;;
"abort") echo abort; break ;;
'#'*=*) echo activate $line;;
*=[0-9]*) echo int value $line;;
*=YES|NO) echo boolean value $line;;
*) echo text value $line ;;
esac
done
Instead of 'echo intvalue $line' you would probably call a function "intconfigure" where only int values are accepted. For "write", you would write back to the file, but I omitted, conserving the comments without assignment and sorting them in again at the right position has to be done, which isn't trivial, given the opportunity to activate or deactivate comments.
But read up on the select command in shell and try it out and see how far you come.
If you think you have reached a usable solution, use this for all your configuration files privately and see, whether you prefer it over using a simple editor or not.

Creating a 'yes' or 'no' menu in UNIX bash shell scripting

I'm currently writing a script, and at one point I want it check if a file already exists. If the file doesn't exist, then it should do nothing. However, if the file does exist, I want a 'y' or 'n' (yes or no) menu to appear. It should ask "Do you want to overwrite this file?".
So far I've tried writing something similar to this. Take into account that before this a function called:
therestore
exists. I want this function to occur if they type "y". Anyway, this is what I tried:
If [ -f directorypathANDfilename ] ; then
read -p "A file with the same name exists, Overwrite it? Type y/n?" yesorno
case $yesorno in
y*) therestore ;;
n*) echo "File has not been restored" ;;
esac
fi
For some reason though, the menu always pops up, even if the file DOESN'T exist and it doesn't restore it properly if I type yes! (But I know the "therestore" function works fine, because I've tested it plenty of times).
Apologies for the long-winded question. If you need any more details let me know - thanks in advance!
Does your script even run? Doesn't look like valid bash-script to me. If is not a valid keyword, but if is. Also, tests go inside angle-brackets [ ], those are not optional. Moreover you forgot the closing fi.
And another thing, it's not quite clear to me what you're testing for. Is directorypathANDfilename a variable? In that case you have to reference it with the $.
The snippet would probably work better like this:
#!/bin/bash
if [ -f "$directorypathANDfilename" ] ; then
read -p "A file with the same name exists, Overwrite it? Type y/n?" yesorno
case "$yesorno" in
y*) therestore ;;
n*) echo "File has not been restored" ;;
esac
fi

How to parametrize verbosity of debug output (BASH)?

During the process of writing a script, I will use the command's output in varying ways, and to different degrees - in order to troubleshoot the task at hand.. For example, in this snippet, which reads an Application's icon resource and returns whether or not it has the typical .icns extension...
icns=`defaults read /$application/Contents/Info CFBundleIconFile`
if ! [[ $icns =~ ^(.*)(.icns)$ ]]; then
echo -e $icns "is NOT OK YOU IDIOT! **** You need to add .icns to "$icns"."
else
echo -e $icns "\t Homey, it's cool. That shits got its .icns, proper."
fi
Inevitably, as each bug is squashed, and the stdout starts relating more to the actual function vs. the debugging process, this feedback is usually either commented out, silenced, or deleted - for obvious reasons.
However, if one wanted to provide a simple option - either hardcoded, or passed as a parameter, to optionally show some, all, or none of "this kind" of message at runtime - what is the best way to provide that simple functionality? I am looking to basically duplicate the functionality of set -x but instead of a line-by rundown, it would only print the notifications that I had architected specificically.
It seems excessive to replace each and every echo with an if that checks for a debug=1|0, yet I've been unable to find a concise explanation of how to implement a getopts/getopt scheme (never can remember which one is the built-in), etc. in my own scripts. This little expression seemed promising, but there is very little documentation re: 2>$1 out there (although I'm sure this is key to this puzzle)
[ $DBG ] && DEBUG="" || DEBUG='</dev/null'
check_errs() {
# Parameter 1 is the return code Para. 2 is text to display on failure.
if [ "${1}" -ne "0" ]; then
echo "ERROR # ${1} : ${2}"
else
echo "SUCESSS "
fi }
Any concise and reusable tricks to this trade would be welcomed, and if I'm totally missing the boat, or if it was a snake, and it would be biting me - I apologize.
One easy trick is to simply replace your "logging" echo comamnd by a variable, i.e.
TRACE=:
if test "$1" = "-v"; then
TRACE=echo
shift
fi
$TRACE "You passed the -v option"
You can have any number of these for different types of messages if you wish so.
you may check a common open source trace library with support for bash.
http://sourceforge.net/projects/utalm/
https://github.com/ArnoCan/utalm
WKR
Arno-Can Uestuensoez

Parsing input options containing whitespaces in a bash script

I have a bash script parsing input option with a block of code like the following
for WORD in "$#" ; do
case $WORD in
--*) true ;
case $WORD in
--opt1=*)
OPT1=${WORD/--opt1=/}
shift ;;
--opt2=*)
OPT2=${WORD/--opt2=/}
shift ;;
*) echo "Unrecognized argument $WORD"
;;
esac ;;
*) echo "Option $WORD not starting with double dash."
;;
esac
done
The script is invoked by another parent program which creates the entire command line.
The output created by this parent program looks like
./childscript.sh "--opt1=value1 --opt2=value2"
The problems appear when the generated line looks like
./childscript.sh "--opt1='value11 value12' --opt2=value2"
The scripts complains saying
Option value12 not starting with double dash.
How can I modify the child bash code to make it understand white spaces inside the input options?
I don't think the generated line is what you think it is.
Your code works completely fine for me if I simply invoke it directly. With added echoes to check that the values are being stored in the right place:
$ ./child.sh --opt1='v1 v2' --opt2='v3 v4'
OPT1='v1 v2'
OPT2='v3 v4'
You should be able to confirm this. Your problem isn't in making the child script accept arguments like these, it's in having the parent script invoke it correctly.
And by the way, you don't actually want to run something like this:
./childscript.sh "--opt1=value1 --opt2=value2"
That will cause that entire string (--opt1=value1 --opt2=value2) to be read as a single argument. I suspect that you haven't told us the full story on the way the parent script is calling this. If you show us those details, we can probably help out more - or maybe this is enough of a hint.

Resources