Unable to print last line in Linux in while loop

Below is my shell script:

printf "10\n-rwxr-xr-x 73\n-rwxr-xr-x 74\n10\n-rwxr-xr-x 75\n-rwxr-xr-x 76" |
while IFS=' '
read -r dirn
do
       echo "dirn :"$dirn
done

Output:

$ ./test.sh
dirn :10
dirn :-rwxr-xr-x 73
dirn :-rwxr-xr-x 74
dirn :10
dirn :-rwxr-xr-x 75

As you can see dirn :-rwxr-xr-x 76 does not get printed.

The exact same code works fine on Aix ksh shell whereas this is bash.

Can you please suggest what is the issue with my code that riun on Linux Redhat bash shell?

Try:

while IFS='\n'

If that doesnt not fix it, try appending a final character at the end of the line.
As in a tailing "\n" or " " (depends on the IFS you had set).

Hope this helps

The problem is not IFS 's contents, which is used as a field separator between the individual fields. Your read is missing the line terminator, usually <LF> (= \n = 0x0A = ^J) which is not printf ed. So read waits for it but runs into an EOF / EOT (as stdin terminates), discards the data read so far, and breaks out of the loop having unprocessed data in the variable(s) (Thanks to MadeInGermany's post#5 for mentioning that). You can

  • add a linefeed <LF> to the printf command
  • switch read to use a different line terminator (which still needs to be printf ed). man bash :

sea's proposal will set IFS to " ", "\", and "n", split input on any collection of those, and eliminate them from input. Set IFS like IFS=$' \n' to make it <space> and <line feed>.

Oops..
I just wanted to change to IFS="\n" , not " \n" .

When read indicates an EOF and the loop ends, it still has read the last incomplete line into the variable.
So you can process it after the loop.

do_dirn(){
  echo "dirn :$dirn"
}
printf "terminated\nincomplete" |
while
  read -r dirn
do
  do_dirn
done
[ -n "$dirn" ] && do_dirn
1 Like

Would you not be better re-writing the loop to have the loop read the data in rather than have it piped to? That might sound confusingly similar, but some shells will start a sub-process when you add a pipe into it. That might mean that the loop is actually in a sub-process and the scoping of variables may not be what you expect. Of course it might just be that your printf statement doesn't have a new-line after the last item.

Could you consider something like the following instead:-

while read variable
do
   echo "I got variable ${variable}"
done < <(printf "item1\nitem2\nthird item\last\n")

This runs the process to generate the input in a subshell and your loop runs in the current process so that values might be more what you expect.

I hope that this helps,
Robin