Reading input files by line using read command in shell scripting skips last line

前端 未结 5 544
日久生厌
日久生厌 2020-12-01 09:51

I usually use the read command to read an input file to the shell script line by line. An example code such as the one below yields a wrong result if a new line isn\'t inser

相关标签:
5条回答
  • 2020-12-01 10:05

    One line answer:

    IFS=$'\n'; for line in $(cat file.txt); do echo "$line" ; done
    
    0 讨论(0)
  • 2020-12-01 10:09
    DONE=false
    until $DONE
    do
      read line || DONE=true
      echo $line
    done < blah.txt
    

    How to use `while read` (Bash) to read the last line in a file if there’s no newline at the end of the file?

    0 讨论(0)
  • 2020-12-01 10:14

    Use while loop like this:

    while IFS= read -r line || [ -n "$line" ]; do
      echo "$line"
    done <file
    

    Or using grep with while loop:

    while IFS= read -r line; do
      echo "$line"
    done < <(grep "" file)
    

    Using grep . instead of grep "" will skip the empty lines.

    Note:

    1. Using IFS= keeps any line indentation intact.

    2. You should almost always use the -r option with read.

    3. Don't read lines with for

    4. File without a newline at the end isn't a standard unix text file.

    0 讨论(0)
  • 2020-12-01 10:25

    read reads until it finds a newline character or the end of file, and returns a non-zero exit code if it encounters an end-of-file. So it's quite possible for it to both read a line and return a non-zero exit code.

    Consequently, the following code is not safe if the input might not be terminated by a newline:

    while read LINE; do
      # do something with LINE
    done
    

    because the body of the while won't be executed on the last line.

    Technically speaking, a file not terminated with a newline is not a text file, and text tools may fail in odd ways on such a file. However, I'm always reluctant to fall back on that explanation.

    One way to solve the problem is to test if what was read is non-empty (-n):

    while read -r LINE || [[ -n $LINE ]]; do
      # do something with LINE
    done
    

    Other solutions include using mapfile to read the file into an array, piping the file through some utility which is guaranteed to terminate the last line properly (grep ., for example, if you don't want to deal with blank lines), or doing the iterative processing with a tool like awk (which is usually my preference).

    Note that -r is almost certainly needed in the read builtin; it causes read to not reinterpret \-sequences in the input.

    0 讨论(0)
  • 2020-12-01 10:27

    Below code with Redirected "while-read" loop works fine for me

    while read LINE
    do
          let count++
          echo "$count $LINE"
    
    done < $FILENAME
    
    echo -e "\nTotal $count Lines read"
    
    0 讨论(0)
提交回复
热议问题