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

Re: reading a file into an array. mapfile? (f)?



On Sep 17, 10:53pm, Rocky Bernstein wrote:
} Subject: reading a file into an array. mapfile? (f)?
} 
} I'd like to a read a file (a zsh script file) into an array fast.

Ending up with what, one line per array entry?  I'm guessing so since
you mention the (f) expansion flag.

} [...] I also know about mapfile which reads the file and turns it
} into a single long zsh string. Question: if the underlying file
} changes, what does mapfile do? Update its data? Keep the original?
} Show something which is indeterminant?

When you reference a hash key in the mapfile hash, zsh calls mmap()
to access the file contents, but immediately allocates enough memory
to contain the data and copies into it.  The file is then unmapped.
This is done because parameter values are stored with zsh's internal
"metafication" already applied, and it's obviously not possible to
metafy the file in place.

If the file is modified during the brief period when zsh has it mapped
and is copying it, you could get indeterminate results.  It probably
depends on the system's mmap() implementation.  After the file has been
copied, zsh no longer pays attention to it.

If you assign a value to a field in the mapfile hash, zsh attempts
to mmap() the the corresponding disk file for writing, and whatever
you assigned replaces the file contents by way of msync().  You can
(I think) assign to slices of the file, but nothing magical is done,
so the entire file is rewritten unless the msync() implementation is
clever.
 
} There is also the zsh parameter expansion operator (f) "a shorthand
} for 'pws:\n:'". But I don't see how to use that with either mapfile or
} input redirection to save this into an array variable short of putting
} this in a loop

It's much simpler than you seem to believe:

lines=( ${(f)mapfile[/path/to/file]} )

Splitting up /etc/termcap this way (17890 lines on my system) takes
a little less than 0.08 seconds on my 3GHz Pentium 4.  Fully parsing
termcap into "shell words" with (z) takes about 0.13 seconds.  For
/usr/share/dict/words (479829 lines), (f) takes about 0.8 seconds but
(z) takes almost 13 seconds.



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