4

Say for example I have a file called "tests",it contains

a
b
c
d

I'm trying to read this file line by line and it should output

a
b
c
d

I create a bash script called "read" and try to read this file by using for loop

#!/bin/bash
for i in ${1}; do //for the ith line of the first argument, do...
   echo $i  // prints ith line
done

I execute it

./read tests

but it gives me

tests

Does anyone know what happened? Why does it print "tests" instead of the content of the "tests"? Thanks in advance.

OKC
  • 181
  • 1
  • 4
  • 13
  • 2
    Does this answer your question? [Looping through the content of a file in Bash](https://stackoverflow.com/q/1521462/608639) – jww Dec 09 '19 at 10:23

3 Answers3

18
#!/bin/bash
while IFS= read -r line; do
  echo "$line"
done < "$1"

This solution can handle files with special characters in the file name (like spaces or carriage returns) unlike other responses.

Gilles Quénot
  • 173,512
  • 41
  • 224
  • 223
  • 3
    For complete non-destructiveness, do `while IFS= read -r line` -- without "IFS=" you will lose leading/trailing whitespace. – glenn jackman Sep 27 '13 at 19:58
  • It is also possible to execute this as a pipeline, as e.g.: `ls -1 | while IFS= read -r line; do ... done`. I also found that a bit easier to follow the sequence. – will Oct 07 '21 at 21:07
10

You need something like this rather:

#!/bin/bash
while read line || [[ $line ]]; do
  echo $line
done < ${1}

what you've written after expansion will become:

#!/bin/bash
for i in tests; do
   echo $i
done

if you still want for loop, do something like:

#!/bin/bash
for i in $(cat ${1}); do
   echo $i
done
bobah
  • 18,364
  • 2
  • 37
  • 70
  • Thanks for answering. Just wondering, is it impossible to do it by using for loop? – OKC Sep 27 '13 at 19:17
  • 1
    @OKC pretty much. @bobah the last line will get skipped if the file doesn't have a trailing newline ... `read line || [ "$line" ];` fixes that – technosaurus Sep 27 '13 at 19:28
  • @OKC, Michael's answer is close to what you were trying to do, but I would not recommend it. It reads the whole file at once and does the equivalent of `set -- $(cat $somefile); while ([ "$1" ]) do stuff;shift;done` note that here $@ would get up to N variables (one for each occurence of a character from $IFS in the input file) ... and could use a LOT of memory for larger files – technosaurus Sep 27 '13 at 19:46
2

This works for me:

#!/bin/sh

for i in `cat $1`
do
    echo $i
done
Michael
  • 2,683
  • 28
  • 30