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

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

Related

when does a file check in linux fail

I am using a check -f in my code to see if a particular file is present.
I suspect that sometimes (maybe in 1 out of 10 cases) it doesn't work as I see some strange errors in that situation.
the code I have is: if [-f /folder/file] do something
else remove something.
in my deployment, /folder/file is always present. so the above file check should always work, but I see in some very rare cases that remove something gets called instead...which is not right. remove something should not get called if the above /folder/file is present.
if /folder/file is present, are there cases where a -f check can still fail? like for instance if either the folder or file is read only or based on permissions??
You must add a space after the [! Between [ and -f
if [ -f "/folder/file" ] ; then
echo "do something"
else
echo "do something else"
fi

Asking for user input in bash to set variable

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

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

How do I check if a PATH is set? And if not, set it from an argument

#!/bin/bash
if[$LD_PATH == ""]
then
export LD_PATH=$1
else
export LD_PATH=$LD_PATH
fi
#excute the program that needs the path
./someProgThatNeedsThePath
i keep getting "cannot open shared object file"
First, your bash syntax is broken due to lack of spaces. First, you would need spaces around the [ and ] closures. If you use the newer alternate double bracket syntax, you don't have to worry about quoting variables you are testing.
#!/bin/bash
if [[ $LD_PATH = "" ]]; then
export LD_PATH="$1"
else
export LD_PATH="$LD_PATH"
fi
But your real problem is not that at all. Since your code is running in a separate bash shell, the code will have no effect on anything you run in the parent shell. In order to do that you would want to build a function:
function add_to_ld_path () {
if [[ -z $LD_PATH ]]; then
export LD_PATH="$1"
fi
}
Add that code to your .profile, then run it with add_to_ld_path /my/path when you want to use it. Note that since your "else" statement wasn't actually doing anything, I removed it. I also replaced your test for a blank string by making your own with quotes with the builtin empty string test.
Next up is what you are actually trying to accomplish. If all you want to do is set the variable if it's empty, UncleAli's solution is very simple. But it might be useful to do something like this:
function add_to_ld_path () {
case ":$LD_PATH:" in
*"$1"*) :;;
*) LD_PATH=$LD_PATH:$1
esac
}
This would check the current path and add the path given if it wasn't already part of the LD_PATH variable, otherwise it would leave it alone.
if [ -z "$LD_PATH" ]
then
export LD_PATH=$1
fi
Will that do the job?

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