[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Option for read to handle incomplete last line
From: |
Greg Wooledge |
Subject: |
Re: Option for read to handle incomplete last line |
Date: |
Sun, 24 Oct 2021 09:42:11 -0400 |
On Sun, Oct 24, 2021 at 06:41:59PM +0900, Koichi Murase wrote:
> > my apologies if there's a much easier solution for the following
> > problem - in this case please let me know!
>
> We can always define a shell function (which would work in all the
> POSIX shells):
>
> read_line() { read line || test -n "$line"; }
> printf '%s' "$input" | while read_line; do printf ' %s\n'; done
You missed -r in your read command, and "$line" in your second printf.
For bash scripts using this, I'd go a little bit fancier:
read_line() {
if (($# == 0)) || [[ ${!#} = -* ]]; then
declare -n _rl_lastvar=REPLY
else
declare -n _rl_lastvar=${!#}
fi
read -r "$@" || test -n "$_rl_lastvar"
}
This gives us a lot more flexibility:
printf %s "$input" | while read_line; do printf '<%s>\n' "$REPLY"; done
printf %s "$input" | while read_line -e; do printf '<%s>\n' "$REPLY"; done
printf %s "$input" | while read_line -r line; do printf '<%s>\n' "$line"; done
printf 'foo bar\nbaz quux' | while read_line a b; do printf '<%s> <%s>\n' "$a"
"$b"; done
printf 'foo&bar\nbaz&quux' | while IFS=\& read_line a b; do printf '<%s>
<%s>\n' "$a" "$b"; done
printf 'foo\0bar\0baz' | while read_line -rd '' line; do printf '<%s>\n'
"$line"; done
printf 'foo bar\nbaz quux' | while read_line -ra arr; do printf '<%s> '
"${arr[@]}"; echo; done
This intentionally skips a trailing incomplete line that has too few
fields, as in:
unicorn:~$ printf 'foo bar\nbaz' | while read_line a b; do printf '<%s> <%s>\n'
"$a" "$b"; done
<foo> <bar>
The incomplete line here only has one field, so the "lastvar" (b) is
empty, and therefore the incomplete line isn't counted. I consider
this a feature, but others may not.
Of course, it's still not perfect, as it won't handle cases like
read_line -t 5
But I refuse to try to write that. The script-writer can simply change
it to read_line -t 5 REPLY or whatever alternative they want.