znaya
znaya

Reputation: 331

BASH: Iterate range of numbers in a for cicle

I want to create an array from a list of words. so, i'm using this code:

for i in {1..$count} 
do
array[$i]=$(cat file.txt | cut -d',' -f3 | sort -r | uniq | tail -n ${i})
done

but it fails... in tail -n ${i}

I already tried tail -n $i, tail -n $(i) but can't pass tail the value of i

Any ideas?

Upvotes: 1

Views: 232

Answers (4)

glenn jackman
glenn jackman

Reputation: 246877

Instead of reading the file numerous times, use the built-in mapfile command:

mapfile -t array < <(cut -d, -f3 file.txt | sort -r | uniq)

Upvotes: 1

Robert Muil
Robert Muil

Reputation: 3085

Just to elaborate on previous answers, this occurs because the 'brace expansion' is the first part of bash's parsing, and never gets repeated: when the braces are expanded, the '$count' is just a piece of text and so the braces are left as is. Then, when '$count' is expanded to a number, the brace expansion never runs again. See here.

If you wanted for some reason to force this brace expansion to happen again, you can use 'eval':

replace the {1..$count} with $(eval echo {1..${count}})

Better, in your case, to do as anubhava suggests.

Upvotes: 1

anubhava
anubhava

Reputation: 785286

It fails because you cannot use a variable in range directive in shell i.e. {1..10} is fine but {1..$n} is not.

While using BASH you can use ((...)) operators:

for ((i=1; i<=count; i++)); do
   array[$i]=$(cut -d',' -f3 file.txt | sort -r | uniq | tail -n $i)
done

Also note removal of useless use of cat from your command.

Upvotes: 1

FatalError
FatalError

Reputation: 54551

Your range is not evaluated the way you are thinking, e.g.:

$ x=10
$ echo {1..$x}
{1..10}

You're better off just using a for loop:

for ((i = 1; i <= count; i++))
do
   # ...
done

Upvotes: 1

Related Questions