Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Slurping a file (was: more spllitting travails)



On Fri, Jan 12, 2024 at 9:39 PM Roman Perepelitsa
<roman.perepelitsa@xxxxxxxxx> wrote:
>
> The standard trick here is to print an extra character after the
> content of the file and then remove it. This works when capturing
> stdout of commands, too.

This actually led me to the best (?) solution:

  IFS= read -rd '' file_content <file

If IFS is not set, newlines are not stripped.  Of course this still
only works if the file does not contain nul bytes, the -d delimiter
has to be something that's not in the file.  Roman's sysread approach
doesn't care (and sysread is exactly the thing I forgot that I was
expecting Roman to remind me of, although we both seem to have
forgotten IFS).

For commands,

  command | IFS= read -rd '' cmd_stdout

also works, thanks to zsh's fork-to-the-left semantics.  This would
not work in other shells.

>     # Reads stdin until EOF and stores all read content in REPLY.
>     # On error, leaves REPLY unmodified and returns 1.
>     function slurp() {
>       emulate -L zsh -o no_multibyte
>       zmodload zsh/system || return
>       local content
>       while true; do
>         sysread 'content[$#content+1]' && continue

You can speed this up a little by using the -c option to sysread to
get back a count of bytes read, and accumulate that in another var to
avoid having to re-calculate $#content on every loop.

>         (( $? == 5 )) || return
>         break
>       done
>       typeset -g REPLY=$content
>     }




Messages sorted by: Reverse Date, Date, Thread, Author