Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

Tags:

bash

newline

eof

Let’s say I have the following Bash script:

while read SCRIPT_SOURCE_LINE; do   echo "$SCRIPT_SOURCE_LINE" done 

I noticed that for files without a newline at the end, this will effectively skip the last line.

I’ve searched around for a solution and found this:

When read reaches end-of-file instead of end-of-line, it does read in the data and assign it to the variables, but it exits with a non-zero status. If your loop is constructed "while read ;do stuff ;done

So instead of testing the read exit status directly, test a flag, and have the read command set that flag from within the loop body. That way regardless of reads exit status, the entire loop body runs, because read was just one of the list of commands in the loop like any other, not a deciding factor of if the loop will get run at all.

DONE=false until $DONE ;do read || DONE=true # process $REPLY here done < /path/to/file.in 

How can I rewrite this solution to make it behave exactly the same as the while loop I was having earlier, i.e. without hardcoding the location of the input file?

like image 236
Mathias Bynens Avatar asked Nov 12 '10 13:11

Mathias Bynens


People also ask

How do I get the last line in bash?

${str##*$'\n'} will remove the longest match till \n from start of the string thus leaving only the last line in input. Show activity on this post. Then, the first line would be ${lines[0]} , and the last line would be ${lines[-1]} .

How do I read the last line of a file in shell?

To look at the last few lines of a file, use the tail command. tail works the same way as head: type tail and the filename to see the last 10 lines of that file, or type tail -number filename to see the last number lines of the file.

How do I read a file line in bash?

Syntax: Read file line by line on a Bash Unix & Linux shell file. The -r option passed to read command prevents backslash escapes from being interpreted. Add IFS= option before read command to prevent leading/trailing whitespace from being trimmed. while IFS= read -r line; do COMMAND_on $line; done < input.


1 Answers

I use the following construct:

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

It works with pretty much anything except null characters in the input:

  • Files that start or end with blank lines
  • Lines that start or end with whitespace
  • Files that don't have a terminating newline
like image 88
Adam Bryzak Avatar answered Sep 19 '22 22:09

Adam Bryzak