Bash string compare cannot match - bash

I want to filter some collections in mongodb to export. But the string compare seems incorrect.
$1 in my case is localhost:17017/mydb
shop is one of the collections in mongodb, but $i == 'shop' never succeed.
#!/bin/bash
colls=`mongo $1 --eval 'db.getCollectionNames();' | tail -1`
IFS=',' read -ra ADDR <<< $colls
for i in "${ADDR[#]}"
do
if [[ $i == 'shop' ]]
then
echo $i
fi
done
Or is there any other methods to export specified collections from mongodb?

Try to echo the values you got and see perhaps how you should actually use the patterns. Also please quote your variables properly. It's also better to use $() over backticks:
#!/bin/bash
colls=$(mongo "$1" --eval 'db.getCollectionNames();' | tail -1)
echo "colls: $colls"
IFS=',' read -ra ADDR <<< "$colls"
echo "colls count: ${#ADDR[#]}"
for i in "${ADDR[#]}"
do
echo "Trying |$i|."
if [[ $i == 'shop' ]]
then
echo "$i"
fi
done

Related

Bash If statement to compare array's variables

Try to figure out how to apply conditions to two variables, one of them read from file and stored into array.
Seems that the problem is the second variable, the one stored into array.
#!/bin/bash
#CHECKTIME
#GET TIME
IFS=- read -r DAY HOUR MINUTE < <(date +%u-%H-%M)
echo $DAY
echo $HOUR
echo $MINUTE
arr=()
while IFS= read -r line; do
arr+=("$line")
done < myFile.txt
echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}
if [ $DAY = $arr[0]]
then
echo "do event"
else
echo "don't do event"
fi
Thanks
The syntax for getting an element of an array is this:
${arr[0]}
Although that's not the only problem with your script. You could use ShellCheck to debug the rest. To start, [ $DAY = $arr[0]] is invalid.
You are mixing zsh and bash syntax here. You if statement would be valid under zsh (although in zsh it should be $arr[1] instead of $arr[0]). In bash, you can do either
if [ "$DAY" = "${arr[0]}" ]
or (if you don't like quoting)
if [[ $DAY == ${arr[0]} ]]

Unix property file read using script

My property file:
a.prop
user=abc
location=home
user=xyz
location=roamer
I need to read a.prop and keep user and location inside a variable so that I can pass them to my other script (check.sh) as an argument.
The check.sh needs to be called for all the list of user/location.
I don't want to use AWK
Here's an extremely fragile, ill-advised solution that invokes a function for each stanza of your config, but requires the exact format of your input and is vulnerable to many, many attack vectors. Use (or, preferrably not) at your own risk!
#!/bin/bash
foo() { echo "user is $user, location is $location"; }
eval "$(sed -e '/^$/s//foo/' input; echo foo)"
You would be much better off pre-processing the input, and a willingness to use awk would be helpful.
untested
while read -r line; do
key=${line%%=*} # the left-hand-side of the =
case $key in
user) user=${line#*=} ;;
location) location=${line#*=} ;;
*) continue ;; # skip this line
esac
if [[ -n $user ]] && [[ -n $location ]]; then
echo "have user=$user and location=$location"
check.sh "$user" "$location"
unset user location
fi
done < a.prop
This version is a little unsafer: just assume the properties are valid shell variable assignments.
while read -r line; do
[[ $line != *=* ]] && continue
declare "$line"
if [[ -n $user ]] && [[ -n $location ]]; then
echo "have user=$user and location=$location"
check.sh "$user" "$location"
unset user location
fi
done < a.prop
Or, assuming "user" always appears before "location"
grep -E '^(user|location)=' a.prop |
while read userline; read locline; do
declare "$userline"
declare "$locline"
echo "have user=$user and location=$location"
check.sh "$user" "$location"
done

[[Bash]] Search for combined Expressions in every row

I am very new to Bash Scripting and I have a question regarding my CheckOurCodingRules.sh script:
I want to search for every 'hPar,' in a textfile and if found it should be checked if there is a also a 'const' in the same row.
Thats what I got so far but there is something wrong here:
while read line
do
if [[ $line == *hPar\,* ]] && [[ $line == *const\*]];then
DOCUMENTATION_TEST_A=1
else
echo DOCUMENTATION_TEST_A=0
fi
done < $INPUT_FILE
if [[DOCUMENTATION_TEST_A=0]];then
echo "error: Rule1: No const before hpar"
fi
There are a couple of issues with your script, see the code below which works for me:
DOCUMENTATION_TEST_A=0 # initial value
while read line
do
# spaces between conditional and brackets, no backslashes
if [[ $line == *hPar,* ]] && [[ $line == *const* ]]
then
DOCUMENTATION_TEST_A=1
break # optional, no need to scan the rest of the file
fi
done < $INPUT_FILE
# spaces and $, -eq is used for numerical comparisons
if [[ $DOCUMENTATION_TEST_A -eq 0 ]];
then
echo "error: Rule1: No const before hpar"
fi
A cleaner solution would be to use grep:
if ! grep "hPar," $INPUT_FILE | grep "const" >/dev/null
then
echo "error: Rule1: No const before hpar"
fi

Bash while loop if statment

Can anyone see whats wrong here? If I put X|9 in lan.db (or any db in this directory) and run the following code, the IF statement does not work. It's weird! if you echo $LINE, it is indeed pulling X|9 out of lan.db (or any db in this directory) and setting it equal to LINE, but it wont do the comparison.
DBREGEX="^[0-9]|[0-9]$"
shopt -s nullglob
DBARRAY=(databases/*)
i=0
for i in "${!DBARRAY[#]}"; do
cat ${DBARRAY[$i]} | grep -v \# | while read LINE; do
echo "$LINE" (Whats weird is that LINE DOES contain X|9)
if [[ !( $LINE =~ $DBREGEX ) ]]; then echo "FAIL"; fi
done
done
If however I just manually sent LINE="X|9" the same code (minus the while) works fine. ie LINE=X|9 fails, but LINE=9|9 succeeds.
DBREGEX="^[0-9]|[0-9]$"
Comment shopt -s nullglob
Comment DBARRAY=(databases/*)
Comment i=0
Comment for i in "${!DBARRAY[#]}"; do
Comment cat ${DBARRAY[$i]} | grep -v \# | while read LINE; do
LINE="X|9"
if [[ !( $LINE =~ $DBREGEX ) ]]; then echo "FAIL"; fi
Comment done
Comment done
* UPDATE *
UGH I GIVE UP
Now not even this is working...
DBREGEX="^[0-9]|[0-9]$"
LINE="X|9"
if [[ ! $LINE =~ $DBREGEX ]]; then echo "FAIL"; fi
* UPDATE *
Ok, so it looks like I have to escape |
DBREGEX="^[0-9]\|[0-9]$"
LINE="9|9"
echo "$LINE"
if [[ ! $LINE =~ $DBREGEX ]]; then echo "FAIL"; fi
This seems to work ok again
| has a special meaning in a regular expression. ^[0-9]|[0-9]$ means "starts with a digit, or ends with a digit". If you want to match a literal vertical bar, backslash it:
DBREGEX='^[0-9]\|[0-9]$'
for LINE in 'X|9' '9|9' ; do
echo "$LINE"
if [[ ! $LINE =~ $DBREGEX ]] ; then echo "FAIL" ; fi
done
You don't need round brackets in regex evaluation. You script is also creating a sub shell and making a useless use of cat which can be avoided.
Try this script instead:
while read LINE; do
echo "$LINE"
[[ "$LINE" =~ $DBREGEX ]] && echo "PASS" || echo "FAIL"
done < <(grep -v '#' databases/lan.db)

Read line by line from different locations please help to avoid duplicated code

I've the following script.
for args
do
while read line; do
# do something
done <"$args"
done
If the script is started with a list of filenames, it should read out each file line by line.
Now I'm looking for a way the read from stdin when script is started without a list of filenames, but I doesn't want to duplicate the while loop.
Any ideas?
Quick answer:
[[ -z $1 ]] && defaultout=/dev/stdin
for f in "$#" $defaultout; do
while read line; do
# do something
done < "$f"
done
Drawback: parameters are not parsed
Second attempt:
[[ -z $1 ]] && defaultout=/dev/stdin
for f in $# $defaultout; do
if [[ -f $f ]]; then
while read line; do
# do something
done < "$f"
fi
done
Drawback: Filenames with spaces will be parsed into two words.
You could try:
args="$*"
if [ "$args" = "" ]; then
args=/dev/stdin;
fi
for arg in $args; do
while read -r line; do
# do something
done < "$arg";
done
The following should do what you want:
cat "$#" | while read line; do
# something
done

Resources