4

I have an input text file looking like:

# string name           |       String type (x,y,or z)

name_1                  |               x
name_2                  |               y
name_3                  |               z

I want to read it and fill

  • A global array containing all the string names
  • Three arrays (say list_x, list_y and list_z) depending on the string type

Here is my script:

# Array initialization
list_global=();list_x=();list_y=();list_z=()
# Remove blank lines if there are some
sed -i '/^[[:space:]]*$/d' input_tab.txt
# Reading file
while read line
do
        name=$(echo $line |awk -F "|" '{print $1}'|sed 's/ //g')
        type=$(echo $line |awk -F "|" '{print $2}'|sed 's/ //g')
        # Checking data are correctly read
        printf "%6s is of type %2s \n" "$name" "$type"

        # Appending to arrays
        list_global+=("$name")

        if [ "$type"==x ]
        then
                list_x+=("$name")
        elif [ "$type"==y ]
        then
                list_y+=("$name")
        elif [ "$type"==z ]
        then
                list_z+=("$name")
        fi

done < input_tab.txt
# Print outcome
echo global_list ${list_global[@]}
echo -e "\n \n \n "

echo list_x ${list_x[@]}
echo list_y ${list_y[@]}
echo list_z ${list_z[@]}

This produces the following output

name_1 is of type  x
name_2 is of type  y
name_3 is of type  z
global_list name_1 name_2 name_3


list_x name_1 name_2 name_3
list_y
list_z

Meaning my input file is correctly read, and the way I fill arrays is valid. I can not get to understand why it would systematically satisfy the first "if" it goes through. If I first test if [ "$type"==z ] then everything goes to list_z.

Notes:

  • Using a switch/case instead of if leads to the same result
  • I run bash 4.1.2

Any help/explanation would be much appreciated, Thanks in advance

EdouardIFP
  • 273
  • 2
  • 10
  • If you don't leave spaces around `==` (or, more portably, `=`) in `[ ]`, the contents are interpreted as a single string and always evaluate to true. Since `case` doesn't include such a comparison, I don't see how you get the same results with `case`. – Benjamin W. Aug 07 '18 at 15:24
  • Side note: instead of `while read line` and then using awk, you can have Bash split your lines: `while read name _ type` removes the whitespace for you. – Benjamin W. Aug 07 '18 at 15:26
  • If you had Bash 4.3 or newer, you could use namerefs and simplify to something like `while read name _ type; do declare -n list=list_$type; list+=("$name"); done` – Benjamin W. Aug 07 '18 at 15:33

1 Answers1

1

This code will fix the issue the issue is really with the syntax what I have changed is the if conditions instead of:

if [ "$type"==x ]

now looks like:

if [ "$type" == "x" ]

so in your case, with your sytax the if condition will always evaluate to be true and that is why it was giving it all to the first list.

# Array initialization
list_global=();list_x=();list_y=();list_z=()
# Remove blank lines if there are some
sed -i '/^[[:space:]]*$/d' remo.txt
# Reading file
while read line
do
        name=$(echo $line |awk -F "|" '{print $1}'|sed 's/ //g')
        type=$(echo $line |awk -F "|" '{print $2}'|sed 's/ //g')
        # Checking data are correctly read
        printf "%6s is of type %2s \n" "$name" "$type"

        # Appending to arrays
        list_global+=("$name")

        if [ "$type" == "x" ]
        then
                list_x+=("$name")

        elif [ "$type" == "y" ]
        then
                list_y+=("$name")

        elif [ "$type" == "z" ]
        then
                list_z+=("$name")
        fi

done < remo.txt
# Print outcome
echo global_list ${list_global[@]}
echo -e "\n \n \n "

echo list_x ${list_x[@]}
echo list_y ${list_y[@]}
echo list_z ${list_z[@]}

The output will be:

list_x name_1
list_y name_2
list_z name_3
Inder
  • 3,711
  • 9
  • 27
  • 42
  • yes did that kindly check – Inder Aug 07 '18 at 15:26
  • Thanks, refresh wasn't showing anything. – ggorlen Aug 07 '18 at 15:27
  • `declare -p list_x list_y list_z` is a better way to emit contents of all the arrays. `echo ${list_x[@]}` can't show you the difference between `list_x=( "foo bar" )` and `list_x=( "foo" "bar" )`, and it doesn't show the difference between `list_x=( '*' )` (a list with a single string containing an asterisk) and `list_x=( * )` (a list of filenames). See also [BashPitfalls #14](http://mywiki.wooledge.org/BashPitfalls#echo_.24foo). – Charles Duffy Aug 07 '18 at 15:31
  • Beyond that, though -- see the section "Answer Well-Asked Questions" in [How to Answer](https://stackoverflow.com/help/how-to-answer), particularly the bullet point regarding questions which "*...have already been asked and answered many times before*". – Charles Duffy Aug 07 '18 at 15:32
  • I'd like to say that this did not work for me. I actually found out that `sed 's/ //g' ` was problematic. I used a parametric expansion to remove blanks instead and it worked. It is not clear why it did even though... Even though, the answer points out a good point so I'll accept this one. – EdouardIFP Aug 10 '18 at 08:53
  • its strange that it didn't work, did you get some other result? can you please share the same? – Inder Aug 10 '18 at 10:07