Bash reading txt file and storing in array

10,126

Solution 1

The first part (where you build the array) looks ok, but the second part has a couple of serious errors:

  • for i in myArray; -- this executes the loop once, with $i set to "myArray". In this case, you want $i to iterate over the indexes of myArray, so you need to use

    for i in "${!myArray[@]}"
    

    or

    for ((i=0; i<${#a[@]}; i++))
    

    (although I generally prefer the first, since it'll work with noncontiguous and associative arrays).

    Also, you don't need the ; unless do is on the same line (in shell, ; is mostly equivalent to a line break so having a semicolon at the end of a line is redundant).

  • if myArray[$i]="$NOME" ; then -- the if statement takes a command, and will therefore treat myArray[$i]="$NOME" as an assignment command, which is not at all what you wanted. In order to compare strings, you could use the test command or its synonym [

    if [ "${myArray[i]}" = "$NOME" ]; then
    

    or a bash conditional expression

    if [[ "${myArray[i]}" = "$NOME" ]]; then
    

    The two are very similar, but the conditional expression has much cleaner syntax (e.g. in a test command, > redirects output, while \> is a string comparison; in [[ ]] a plain > is a comparison).

    In either case, you need to use an appropriate $ expression for myArray, or it'll be interpreted as a literal. On the other hand, you don't need a $ before the i in "${myArray[i]}" because it's in a numeric expression context and therefore will be expanded automatically.

    Finally, note that the spaces between elements are absolutely required -- in shell, spaces are very important delimiters, not just there for readability like they usually are in c.

Solution 2

1.-This is what you wrote with small adjustments

#!/bin/bash

NOME=$1

#IF NAME IS FOUND IN THE PHONE-BOOK **THEN** READ THE PHONE BOOK LINES INTO AN ARRAY VARIABLE
#ONCE THE ARRAY IS COMPLETED, GET THE INDEX OF MATCHING LINE AND RETURN ARRAY[INDEX+1]

c=0
if grep "$NOME" /root/phonebook.txt ; then

       echo "CREATING ARRAY...."
       IFS= while read -r line    #IFS= in case you want to preserve leading and trailing spaces
       do
             myArray[c]=$line     # put line in the array
             c=$((c+1))           # increase counter by 1
       done < /root/phonebook.txt


       for i in ${!myArray[@]}; do
             if  myArray[i]="$NOME" ;  then
                 echo ${myArray[i+1]} >> /root/numbertocall.txt
             fi
       done


else
       echo "Name not found"
fi

2.-But you can also read the array and stop looping like this:

#!/bin/bash

NOME=$1

c=0
if grep "$NOME" /root/phonebook.txt ; then

       echo "CREATING ARRAY...."
       readarray myArray < /root/phonebook.txt


       for i in ${!myArray[@]}; do
             if  myArray[i]="$NOME" ;  then
                 echo ${myArray[i+1]} >> /root/numbertocall.txt
                 break            # stop looping
             fi
       done


else
       echo "Name not found"
fi
exit 0

3.- The following improves things. Supposing a)$NAME matches the whole line that contains it and b)there's always one line after a $NOME found, this will work; if not (if $NOME can be the last line in the phone-book), then you need to do small adjustments.

!/bin/bash
PHONEBOOK="/root/phonebook.txt"
NUMBERTOCALL="/root/numbertocall.txt"
NOME="$1"
myline=""

myline=$(grep -A1 "$NOME" "$PHONEBOOK" | sed '1d')

if [ -z "$myline" ]; then 
      echo "Name not found :-("

else
      echo -n "$NOME FOUND.... "
      echo "$myline" >> "$NUMBERTOCALL"
      echo  " .... AND SAVED! :-)"

fi
exit 0
Share:
10,126
Aaron Ullal
Author by

Aaron Ullal

Updated on June 06, 2022

Comments

  • Aaron Ullal
    Aaron Ullal almost 2 years

    I'm writing my first Bash script, I have some experience with C and C# so I think the logic of the program is correct, it's just the syntax is so complicated because apparently there are many different ways to write the same thing!

    Here is the script, it simply checks if the argument (string) is contained in a certain file. If so it stores each line of the file in an array and writes an item of the array in a file. I'm sure there must be easier ways to achieve that but I want to do some practice with bash loops

    #!/bin/bash
    
    NOME=$1
    c=0
    
    #IF NAME IS FOUND IN THE PHONEBOOK THEN STORE EACH LINE OF THE FILE INTO ARRAY
    #ONCE THE ARRAY IS DONE GET THE INDEX OF MATCHING NAME AND RETURN ARRAY[INDEX+1]
    
    if grep "$NOME" /root/phonebook.txt ; then
            echo "CREATING ARRAY"
            while read line
            do
                    myArray[$c]=$line # store line
                    c=$(expr $c + 1) # increase counter by 1
            done < /root/phonebook.txt
    
    else
            echo "Name not found"
    fi
    
    c=0
    for i in myArray;
            do
                  if   myArray[$i]="$NOME" ;  then
                     echo ${myArray[i+1]} >> /root/numbertocall.txt
                  fi
    
    done
    

    This code returns the only the second item of myArray (myArray[2]) or the second line of the file, why?