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.