Solved Shell script to read the no of words in each line

February 21, 2012 at 23:51:53
Specs: CentOS
My input is in the form of a text file from which i will be reading the data, word by word in each line.
However, the no of words in each line differs, and i need to read each word and assign it to a variable in an array

My input file is something like this

aaa x123 aaa@123
xxa x234 xxa@123 file12
sss x125
ccc x789 ccc@123 file22 read_write

I need a function to read each word in a line till the end of that line and store it in an array, and i'll call that function within a loop using the no of lines in the file.


The code i'm expecting is like this

#!/bin/sh
a=0
lines=$(wc -l < filename)
while [ $a -lt $lines ]
do
#code to read the words in that line
a=`expr $a + 1`
done


Please help


See More: Shell script to read the no of words in each line

Report •

✔ Best Answer
February 27, 2012 at 16:27:02
You are welcome and I am glad you have solved your problem. But this is an interesting problem and I do have an update.

First, since you are using CentOS Linux, I am almost certain you are using the bash shell. Perform a long listing on /bin/sh, ls -l, and probably you'll see a link to the bash shell:

lrwxrwxrwx 1 root root 4 Sep 11 2009 /bin/sh -> bash

Second, you are correct about my ksh code not working. Shell arrays are not portable as they work differently with bash. Under bash, you can build an array as such:

my_array=(item1 item2 item3)

echo ${my_array[0]}
echo ${my_array[1]}
echo ${my_array[2]}

A dynamic array can be built by echoing a line of input delimited by spaces:

#!/bin/bash

# dynamically build the arrays
n=1
while read line
do
   eval word${n}=\($(echo $line) \)
   n=`expr $n + 1`
done < inputfile

# show the first array
# echo ${word1[0]}
# echo ${word1[1]}
# echo ${word1[2]}

# dynamically print the arrays
cnt=0
while [ $cnt -lt $n ]
do
   # what is the array length
   eval len=\"\${#word${cnt}[@]}\"
   arrcnt=0
   while [ $arrcnt -lt $len ]
   do
      eval echo \${word${cnt}[${arrcnt}]}
      arrcnt=`expr $arrcnt + 1`
   done
   echo
   cnt=`expr $cnt + 1`
done



#1
February 22, 2012 at 06:19:11
Hey, I've just developed a code that solves this problem, but it has created some new ones.

My code has evolved a bit, and so have my requirements.

I've used the following code to separate the words in each line and print them out.

while read line
do
echo -e ${line} | tr ' ' '\n' > temp.txt
done < inputfile

But assigning them to an array is being a problem here, since i need to store the words of the first line in an array called word1[*], words of 2nd line in word2[*] and so on.

Every Nth word of Mth line will be in array wordM[N]

ie, first word of line 1 will be stored in word1[1], second word of line 1 in word1[2] and so on. Thus, for eg, 3rd word of the 4th line will be in word4[3]

I've tried using a code like this,

n=1
while read line
do
echo -e ${line} | tr ' ' '\n' > temp.txt
i=0
while read word
do
word$n[i]=$word # error occurs here
i=`expr $i + 1`
done < temp.txt
n=`expr $n + 1`
done < input.txt

But the line word$n[i]=$word keeps throwing a "command not found" error.
Is there any way to overcome this?

Please help.


Report •

#2
February 22, 2012 at 12:16:35
First, your use of sh and expr leads me to think you are using the Bourne shell. That's not necesarrily true, but if you are, the standard Bourne does not support arrays. The Korn and Bash shells do; You are asking to create dynamic arrays and it is terribly messy as you can see below.

Also, I chose to use the xargs command which eliminated the need for the temp.txt file. Let me know if you have any questions:

#!/bin/ksh

n=1
while read line
do
   i=1
   echo $line|xargs -n 1|while read word
      do
         # create a dynamic array
         eval word${n}[i]="\$word"
         i=`expr $i + 1`
      done
   n=`expr $n + 1`
done < inputfile

# show the first array
# echo ${word1[1]}
# echo ${word1[2]}
# echo ${word1[3]}

# dynamically print the arrays
cnt=1
while [ $cnt -lt $n ]
do
   # what is the array length
   eval len=\"\${#word${cnt}[@]}\"
   arrcnt=1
   while [ $arrcnt -le $len ]
   do
      eval echo \${word${cnt}[${arrcnt}]}
      arrcnt=`expr $arrcnt + 1`
   done
   echo
   cnt=`expr $cnt + 1`
done


Report •

#3
February 23, 2012 at 23:21:40
Nails,

Thanks a lot for your help. I understand how tough and messy working with dynamic arrays is. I've been breaking my head over this problem for the past few days.

I tried executing your code. It does not throw any errors, but at the same time, does not display any output either.

And i'm still doubtful about arrays and Bourne shell, because i executed a sample program using arrays and it works just fine.

The sample program i used was like this

#!/bin/sh

NAME[0]="AAA"
NAME[1]="BBB"
NAME[2]="CCC"
NAME[3]="DDD"
NAME[4]="EEE"
echo "First Method: ${NAME[*]}"
echo "Second Method: ${NAME[@]}"

The output i get is as follows

First Method: AAA BBB CCC DDD EEE
Second Method: AAA BBB CCC DDD EEE


I'm still not sure why your script isn't displaying any output, since i'm new to shell scripting and i don't have a complete understanding of all the commands.

Please Help.


Report •

Related Solutions

#4
February 24, 2012 at 01:45:00
Nails,

After taking a close look at your code, I've sorted out the issue with my code.

This line was throwing an error
word$n[i]=$word

I just changed it to
eval word${n}[$i]="$word"

and i'm not getting that error anymore.

Still, displaying them is an issue. Any advice on how to display them using a loop?


Report •

#5
February 24, 2012 at 13:34:16
I stand by my statement that standard Bourne shell does not support arrays. See this link:

http://docstore.mik.ua/orelly/unix/...


I tried your array program from reply #3. It worked on my Solaris 9 ksh and failed with the Bourne shell.

What OS are you using? If you are using BSD or FreeBSD, sh on these OS versions are not standard Bourne which is why arrays are working.

First, after building an array are you able to print out an array explicitly?:

# show the first array
echo ${word1[1]}
echo ${word1[2]}
echo ${word1[3]}

Second, my original post is successfully displaying dynamically arrays in a loop. Since I don't have your OS and shell, there really isn't anything else I can do.


Report •

#6
February 26, 2012 at 23:09:59
Nails,

I'm using CentOS 5. I'm not sure if my OS has the standard version of Bourne or not.

Anyway, i've got my code to work since i just realised that i only have to assign the values to the array variables to pass them to another function and there is no need to display these values.

Thanks a lot for your time and your help.


Report •

#7
February 27, 2012 at 16:27:02
✔ Best Answer
You are welcome and I am glad you have solved your problem. But this is an interesting problem and I do have an update.

First, since you are using CentOS Linux, I am almost certain you are using the bash shell. Perform a long listing on /bin/sh, ls -l, and probably you'll see a link to the bash shell:

lrwxrwxrwx 1 root root 4 Sep 11 2009 /bin/sh -> bash

Second, you are correct about my ksh code not working. Shell arrays are not portable as they work differently with bash. Under bash, you can build an array as such:

my_array=(item1 item2 item3)

echo ${my_array[0]}
echo ${my_array[1]}
echo ${my_array[2]}

A dynamic array can be built by echoing a line of input delimited by spaces:

#!/bin/bash

# dynamically build the arrays
n=1
while read line
do
   eval word${n}=\($(echo $line) \)
   n=`expr $n + 1`
done < inputfile

# show the first array
# echo ${word1[0]}
# echo ${word1[1]}
# echo ${word1[2]}

# dynamically print the arrays
cnt=0
while [ $cnt -lt $n ]
do
   # what is the array length
   eval len=\"\${#word${cnt}[@]}\"
   arrcnt=0
   while [ $arrcnt -lt $len ]
   do
      eval echo \${word${cnt}[${arrcnt}]}
      arrcnt=`expr $arrcnt + 1`
   done
   echo
   cnt=`expr $cnt + 1`
done


Report •

#8
February 27, 2012 at 22:49:20
Nails,

Wow. That script just works like a charm. Thanks for clearing that up.

Since i'm relatively new to Linux, I'm still exploring tha various capabilities of shell and there's a lot more I have to learn. That's why I was unable to provide my exact system specs the first time.

Thanks again for solving this issue. I was onto this for almost a week.


Report •

Ask Question