If statement string comparison - if-statement

What am I'm doing wrong over here?
The script by default enters this IF statement & displays the echo statement to exit.
#!/bin/ksh
server=$1
dbname=$2
IFS="
"
if [[ "${dbname}" != "abc_def_data" || "${dbname}" != "abc_def01_data" ]]; then
echo "Msg: Triggers can only be applied to CMS_JAD:abc_def_data/abc_def01_data!"
exit 0
fi

chaining of != conditions requires some inversion of thinking.
I much prefer a clearer path to testing these conditions by using the case ... esac structure.
case "${dbname}" in
abc_def_data|abc_def01_data )
#dbg echo "matched, but for real code replace with just a ':' char"
:
;;
* )
echo "didn_t match any expected values for \$dbname"
echo exit 1
;;
esac
Note that as you're really trying to find the *) case, the actions for the abc_def_data (etc) match can be anything, but to just skip to the next section of code, you would only need the shell's null cmd : .
Edit 1
Note that I have echo exit 1, just so if you copy/paste this to a command line, your shell won't exit. In real code, remove the echo and expect the exit to work.
Edit 2
Also, note that the | char in the case match (abc_def_data**|**abc_def01_data) is essentially an OR (I think it is called something else in the "case match" context).
IHTH

Did you, by any chance, meant to write this?
if [[ "${dbname}" != "abc_def_data" && "${dbname}" != "abc_def01_data" ]]; then
echo "Msg: Triggers can only be applied to CMS_JAD:abc_def_data/abc_def01_data!"
exit 0
fi

try this man, it should work just fine you should have seperated the conditions with "[ ]" and used -o instead of ||....
btw it worked for me fine...
server=$1
dbname=$2
IFS=""
if [ "${dbname}" != "abc_def_data" ] -o [ "${dbname}" != "abc_def01_data" ]
then
echo "Msg: Triggers can only be applied to CMS_JAD:abc_def_data/abc_def01_data!"
exit 0
fi

Related

shell wrapper to restart script based on its output

I've had a bit of shell scripting practice reading piped input from other programs, but am unsure how to approach this problem.
THE BACKSTORY
A program robinbotter whose internals I can't really fix/modify takes its input from files equities.sym and blacklist.sym, each simple text files containing one ticker symbol per line.
When it runs okay, its output produces:
...
Downloading instruments: [ AFL KELYB LFUS ]
...
When it breaks due to internal bugs,
...
Downloading instruments: [ AFL KELYB LFUS LNVGY
and halts there, with no further output, yielding exit code 0 like in the okay case (unfortunately).
The ticker symbols are printed out with slight delay--no newlines in between--while the program is processing them.
When it hits LNVGY or unpredictably any other many possibilities, somehow it can't handle or at least skip them, instead crashing with no proper exception nor error code.
THE QUESTION
I'm trying to write a minimalistic wrapper script in BASH (eg. retryRB.sh ./robinbotter) which:
Somehow monitors the live unbuffered output of robinbotter, using a regex or other method to detect when output of a line containing "Downloading instruments: [ " doesn't end with "]" before the program ends. In which case:
Take the last symbol printed out (eg. LNVGY) which crashes the program, and append it to the bottom of file blacklist.sym. Like with
echo $lastSymbol >> blacklist.sym
Restart the program robinbotter, retaining its original command-line parameters: $#
I am familiar with tools like awk and sed, and would be open to building a short solution in Ruby if Bash doesn't cut it.
Here you have a Bash version of a code that imitates what your binary does.
then you have a wrapper which logs when the apps successfully completes, and also, when it fails. On failure, it also appends the last item printed, as you can see in the images below ( in this case Im hard-coding a failure on Bomb! and Boom! but you get the idea):
main.sh
#!/bin/bash
some=('Pera' 'Manzana' 'Frutilla' 'Durazno' 'Banana' 'Lechuga' 'Sandia' 'Papa' 'Melon' 'Milanesa' 'Bomb!' 'Boom!')
printf 'Downloading instruments: [ '
for (( i=1 ; i < 5 ; i++ )) {
item=${some[$( shuf -i 0-$(( ${#some[#]} - 1 )) -n 1 )]}
printf "$item"
[[ $item == 'Bomb!' || $item == "Boom!" ]] && exit || printf "$item"
[[ $i -lt 4 ]] && printf ' '
}
printf ' ]'
wrapper.sh
#!/bin/bash
while :
do
res=$( ./main.sh )
[[ ! "$res" =~ \[[^]]*\] ]] && printf "Failure : ${res##*[\[ ]}" || printf "Success"
printf '\n'
sleep 1
done
You can test these scripts and then put your binary in place of main.sh.
Regards!

Regular expressions don't work as expected in bash if-else block's condition

My pattern defined to match in if-else block is :
pat="17[0-1][0-9][0-9][0-9].AUG"
nln=""
In my script, I'm taking user input which needs to be matched against the pattern, which if doesn't match, appropriate error messages are to be shown. Pretty simple, but giving me a hard time though. My code block from the script is this:
echo "How many days' AUDIT Logs need to be searched?"
read days
echo "Enter file name(s)[For multiple files, one file per line]: "
for(( c = 0 ; c < $days ; c++))
do
read elements
if [[ $elements =~ $pat ]];
then
array[$c]="$elements"
elif [[ $elements =~ $nln ]];
then
echo "No file entered.Run script again. Exiting"
exit;
else
echo "Invalid filename entered: $elements.Run script again. Exiting"
exit;
fi
done
The format I want from the user for filenames to be entered is this:
170402.AUG
So basically yymmdd.AUG (where y-year,m-month,d-day), with trailing or leading spaces is fine. Anything other than that should throw "Invalid filename entered: $elements.Run script again. Exiting" message. Also I want to check if if it is a blank line with a "Enter" hit, it should give an error saying "No file entered.Run script again. Exiting"
However my code, even if I enter something like "xxx" as filename, which should be throwing "Invalid filename entered: $elements.Run script again. Exiting", is actually checking true against a blank line, and throwing "No file entered.Run script again. Exiting"
Need some help with handling the regular expressions' check with user input, as otherwise rest of my script works just fine.
I think as discussed in the comments you are confusing with the glob match and a regEx match, what you have defined as pat is a glob match which needs to be equated with the == operator as,
pat="17[0-1][0-9][0-9][0-9].AUG"
string="170402.AUG"
[[ $string == $pat ]] && printf "Match success\n"
The equivalent ~ match would be to something as
pat="17[[:digit:]]{4}\.AUG"
[[ $string =~ $pat ]] && printf "Match success\n"
As you can see the . in the regex syntax has been escaped to deprive of its special meaning ( to match any character) but just to use as a literal dot. The POSIX character class [[:digit:]] with a character count {4} allows you to match 4 digits followed by .AUG
And for the string empty check do as suggested by the comments from Cyrus, or by Benjamin.W
[[ $elements == "" ]]
(or)
[[ -z $elements ]]
I would not bug the user with how many days (who want count 15 days or like)? Also, why only one file per line? You should help the users, not bug them like microsoft...
For the start:
show_help() { cat <<'EOF'
bla bla....
EOF
}
show_files() { echo "${#files[#]} valid files entered: ${files[#]}"; }
while read -r -p 'files? (h-help)> ' line
do
case "$line" in
q) echo "quitting..." ; exit 0 ;;
h) show_help ; continue;;
'') (( ${#files} )) && show_files; continue ;;
l) show_files ; continue ;;
p) (( ${#files} )) && break || { echo "No files enterd.. quitting" ; exit 1; } ;; # go to processing
esac
# select (grep) the valid patterns from the entered line
# and append them into the array
# using the -P (if your grep know it) you can construct very complex regexes
files+=( $(grep -oP '17\d{4}.\w{3}' <<< "$line") )
done
echo "processing files ${files[#]}"
Using such logic you can build really powerful and user-friendly app. Also, you can use -e for the read enable the readline functions (cursor keys and like)...
But :) Consider just create a simple script, which accepts arguments. Without any dialogs and such. example:
myscript -h
same as above, or some longer help text
myscript 170402.AUG 170403.AUG 170404.AUG 170405.AUG
will do whatever it should do with the files. Main benefit, you could use globbing in the filenames, like
myscript 1704*
and so on...
And if you really want the dialog, it could show it when someone runs the script without any argument, e.g.:
myscript
will run in interactive mode...

Shell: Checking if argument exists and matches expression

I'm new to shell scripting and trying to write the ability to check if an argument exists and if it matches an expression. I'm not sure how to write expressions, so this is what I have so far:
#!/bin/bash
if [[ -n "$1"] && [${1#*.} -eq "tar.gz"]]; then
echo "Passed";
else
echo "Missing valid argument"
fi
To run the script, I would type this command:
# script.sh YYYY-MM.tar.gz
I believe what I have is
if the YYYY-MM.tar.gz is not after script.sh it will echo "Missing valid argument" and
if the file does not end in .tar.gz it echo's the same error.
However, I want to also check if the full file name is in YYYY-MM.tar.gz format.
if [[ -n "$1" ]] && [[ "${1#*.}" == "tar.gz" ]]; then
-eq: (equal) for arithmetic tests
==: to compare strings
See: help test
You can also use:
case "$1" in
*.tar.gz) ;; #passed
*) echo "wrong/missing argument $1"; exit 1;;
esac
echo "ok arg: $1"
As long as the file is in the correct YYYY-MM.tar.gz format, it obviously is non-empty and ends in .tar.gz as well. Check with a regular expression:
if ! [[ $1 =~ [0-9]{4}-[0-9]{1,2}.tar.gz ]]; then
echo "Argument 1 not in correct YYYY-MM.tar.gz format"
exit 1
fi
Obviously, the regular expression above is too general, allowing names like 0193-67.tar.gz. You can adjust it to be as specific as you need it to be for your application, though. I might recommend
[1-9][0-9]{3}-([1-9]|10|11|12).tar.gz
to allow only 4-digit years starting with 1000 (support for the first millennium ACE seems unnecessary) and only months 1-12 (no leading zero).

if statement referring to a word errors with - [: !=: unary operator expected

When running my bash script it spits out this error [: !=: unary operator expected when running through it.
In this function:
function undeploy {
echo Removing ${SITE} from ${i} ....
rm -rf /net/${i}/${JBPATH}/${FILEOLD}
if [ $? -ne 0 ] ; then
echo "Nothing to remove, proceeding to copy new WAR"
else
echo "WAR removed, waiting for Undeploy...."
tail -1f /net/${i}/var/log/jboss/server.log | while read LINE ; do if [[ "${LINE}" =~ "Undeployed" ]] ; then if [[ ${LINE} =~ "${SITE}" ]] ; then break ; fi ; fi ; done
check
fi
if [ $4 != force ]; then
echo "Un-deployment completed ${i}. Continue?"
read Continue
case "${Continue}" in
Y|y|yes|YES|Yes) echo "Continuing"
;;
*) echo "Exiting"
exit 1
;;
esac
fi
}
The line if [ $4 != force ]; then causes the error.
Does anyone know why? I have tried putting force and $4 in single and double quotes. Still no luck.
Any ideas of what has gone wrong with the syntax here?
If you require further information, please ask.
It likely to fail if there's no ${4} variable defined (if less than 4 variables are passed to the script). Try using case, or doing another test to see if $4 is present.
exmaple: if [ $# -ge 4 ] ; then (your function)
if [ -n $4 ] ; then (your function)

Parsing OPTARG inside case with regular expression and [[ ]]'s

So, I'm setting up a bash script and want to parse arguments to certain flags using getopts. For a minimal example, consider the a script which has a flag, -M, and it takes y or n as an argument. If I use the following code:
#!/bin/bash
# minimalExample.sh
while getopts "M:" OPTION;
do
case ${OPTION} in
M)
RMPI=${OPTARG}
if ! [[ "$RMPI" =~ "^[yn]$" ]]
then
echo "-M must be followed by either y or n."
exit 1
fi
;;
esac
done
I get the following:
$ ./minimalExample.sh -M y
-M must be followed by either y or n.
FAIL: 1
However, if I use the following code instead
#!/bin/bash
# minimalExample2.sh
while getopts "M:" OPTION;
do
case ${OPTION} in
M)
RMPI=${OPTARG}
if [ -z $(echo $RMPI | grep -E "^[yn]$") ]
then
echo "-M must be followed by either y or n."
exit 1
else
echo "good"
fi
;;
esac
done
I get:
$ ./minimalExample2.sh -M y
good
Why doesn't minimalExample.sh work?
quoting regexp in this context forces a string comparison.
change to
if ! [[ "$RMPI" =~ ^[yn]$ ]]
check following post for more details,
bash regex with quotes?
Why do you need regex here at all? -M y is not the same as -M n, is it? So you definitely will use some statement (case or if) to distinguish one from another.
#!/bin/bash
while getopts "M:" OPTION; do
case ${OPTION} in
M)
case ${OPTARG} in
y)
# do what must be done if -M y
;;
n)
# do what must be done if -M n
;;
*)
echo >&2 "-M must be followed by either y or n."
exit 1
;;
;;
esac
done
Please note >&2 – error messages should be output to STDERR, not to STDOUT.