2

I'm reading the contents of a file and storing them in 2 variables then simultaneously want to compare it with an array using if statement. Code is given below

#!/bin/bash

# Define File

datafile=./regions-with-keys

# Create Nodes File

cat << EOF > $datafile

region1 key1
region2 key2
region3 key3



EOF


# User Input
clear;
echo -ne "PLEASE SELECT REGIONS(s) :\n\033[37;40m[Minimum 1 Region Required]\033[0m"

read -ra a
echo "${a[@]}"


# Reading Regions & Keys

for i in "${a[@]}"
do
    while read -r $b $c; do

        if [ "${a[@]}" -eq "$b" ]; then
            echo "$b" "$c"
        fi

    done < $datafile
done;

it gives command not found for if statement when executed.. Aim of the code is to match the array indexes of userinput with $a from $datafile, if match is successful print $b and $c

Sollosa
  • 379
  • 4
  • 13
  • See https://ss64.com/bash/test.html. Also - quote your variables, see https://mywiki.wooledge.org/Quotes. – Ed Morton May 14 '19 at 12:16
  • 1
    The value in `${regionUser[@]}` is not found in your PATH. You probably meant to write `if test ...` – William Pursell May 14 '19 at 12:23
  • Have a look at http://www.shellcheck.net and fix first all issues mentioned by this tool. Also realize that it should be `if [[ blabla -eq blabla ]]; then` – kvantour May 14 '19 at 12:31
  • @WilliamPursell regionUser is an array assembled by user input at the start. – Sollosa May 14 '19 at 12:33
  • Yes, and you are attempting to invoke the command specified in `${regionUser[0]}`. You probably don't intend to do that, but instead want to invoke some command that makes a comparison. eg `test` (also commonly written `[`) – William Pursell May 14 '19 at 12:39
  • 1
    Dont you want to run the condition in your `if` on variable `$i` not on your full array `"${regionUser[@]"`. Otherwise what's the point of that outer loop? – JNevill May 14 '19 at 12:47
  • @JNevill I want to run it on userinput array, fetch each value, compare it with values in $datafile. Now I've simplified Q and added more details. – Sollosa May 14 '19 at 12:49
  • 1
    If you want to compare each value from the user input array that you are looping through then I would anticipate that you would find each of those values in variable `$i` that you declare in your `for` loop. Otherwise looping your array is sort of superfluous. `for i in "${1[@]}"` says "Loop through each element in my array $1 and put the element in this iteration in variable $i". [see here for example](https://www.cyberciti.biz/faq/bash-for-loop-array/) – JNevill May 14 '19 at 12:59
  • @JNevill got your point, but what's best way to compare these 2 arrays? – Sollosa May 14 '19 at 13:01
  • 1
    Instead of the while loop, perhaps you can toss some awk at it: `awk -v region="$i" 'region==$1{print $0}' "$datafile"` Which will print the line from the file if the first column in the file is equal to the region that is being iterated from the user input array. – JNevill May 14 '19 at 13:40

1 Answers1

1

Try this Shellcheck-clean code:

#!/bin/bash -p

# Define File
datafile=./regions-with-keys

# Create Nodes File
cat <<EOF >"$datafile"
region1 key1
region2 key2
region3 key3
EOF

# User Input
clear
echo 'PLEASE SELECT REGIONS(s) :'
echo -ne '\e[37;40m[Minimum 1 Region Required]\e[0m'

read -ra input_regions
declare -p input_regions

# Reading Regions & Keys
for input_rgn in "${input_regions[@]}" ; do
    while read -r data_rgn key ; do
        if [[ $data_rgn == "$input_rgn" ]] ; then
            printf '%s %s\n' "$data_rgn" "$key"
        fi
    done <"$datafile"
done

Significant changes from the code in the question are:

  • Use meaningful variable names.
  • Use declare -p input_regions to print the contents of the array in an unambiguous way.
  • Use varname instead of $varname as arguments to read. That fixes a serious bug in the original code.
  • Use printf instead of echo for printing variable values. See Why is printf better than echo?.
  • Used [[ ... == ...]] instead of [ ... -eq ... ] for comparing the region names.
    [[ ... ]] is more powerful than [ ... ]. See Is double square brackets [[ ]] preferable over single square brackets [ ] in Bash?. Also, -eq is for comparing integers and == (or, equivalently, =) is for comparing strings.
  • Did various cleanups (removed some blank lines, removed unnecessary semicolons, ...).
  • The new code is Shellcheck-clean. Shellcheck identified several problems with the original code.

If you want to report incorrect input regions, try replacing the "Reading Regions & Keys" code with this:

for input_rgn in "${input_regions[@]}" ; do
    # Find the key corresponding to $input_rgn
    key=
    while read -r data_rgn data_key ; do
        [[ $data_rgn == "$input_rgn" ]] && key=$data_key && break
    done <"$datafile"

    if [[ -n $key ]] ; then
        printf '%s %s\n' "$input_rgn" "$key"
    else
        printf "error: region '%s' not found\\n" "$input_rgn" >&2
    fi
done
pjh
  • 6,388
  • 2
  • 16
  • 17
  • ty pjh, but one thing to clarify. why am I getting this line after I input any region;? declare -a input_regions='([0]="region1")' – Sollosa May 15 '19 at 05:28
  • Also I'm trying to add else part to if, which prints if region does not match, "region doesn't exist" but I'm getting multiple lines, guess due to loop, but I want it single time only, am trying to use sort & uniq but is not working with printf. – Sollosa May 15 '19 at 06:11
  • @Sollosa, `declare -a input_regions='([0]="region1")'` is the output of `declare -p input_regions`. It means that `input_regions` is an array (`declare -a`) containing the string `"region1"` at index zero (`([0]="region1"`). `declare -p` is a useful debugging aid because variables often don't contain what you expect. – pjh May 15 '19 at 11:39
  • 1
    @Sollosa, I've added code for reporting incorrect input regions to the answer. If you have Bash version 4.0 or later, the code could be simplified by using an associative array instead of looping over the data file multiple times. Let me know if you are interested and I will add some example code. I don't know what you are trying to do with `sort` and `uniq` (note that `sort -u` can do both at once) so I can't say what might be going wrong. – pjh May 15 '19 at 11:59
  • ty amigo.. I was printing without region variable, that's why was getting region does not exist several times. And yes Id want bash 4 variations too. One more thing, can we place the user prompt with a loop, so that all values are verified and code moves forward, else prompt user to replace whichever region does not exis. Lets say user puts regio1 region2 abc in prompt, so loop should verify 2 regions and prompt to replace abc with 3rd region, region1 region2 will be stored in array before prompting for 3rd input. And if 3rd input is valid after comparison, it'll be appended at array's ne – Sollosa May 16 '19 at 06:33
  • (Cont.)..next index. – Sollosa May 16 '19 at 06:35