ZSH Gem #22: Accessing and editing files with mapfile
Working on the shell is often working with files and sometimes you need to read or edit their contents. Normally you'd do that with the command line editor of your choice (e.g. nano, vi, vim or emacs), but sometimes you need to write the output of a command or a pipe to a file or feed programs with contents from the hard disk. That's usually done by using the input and output redirection operators, but ZSH gives you one more tool which can sometimes make things easier. This module is called mapfile
.
Since mapfile
is a ZSH module you need to enable it before you can use it:
zmodload zsh/mapfile
Once the module is loaded, you get the magic associative array $mapfile
which gives you direct access to any file when you specify its name as the name of the array key. For example, to echo
the contents of the file examplefile
run
echo $mapfile[examplefile]
You can also write to files by assigning values to an entry of the array. The value will then be written to disk. If the file does not exist yet, it will be created. To write the string Hello World to our file, run
$mapfile[examplefile]="Hello World"
That's the basics and about everything mapfile
can do. How do we make use of it? mapfile
can sometimes be a nice thing when you need to work with contents of a file in a very simple way. By using mapfile
you can avoid piping the contents through chains of commands or doing stuff like this:
filecontents=$(cat file)
mapfile
also enables you to do some basic filtering and editing directly when accessing the file by using ZSH's parameter expansion operators. For example if you need the contents of a file converted to all lowercase, the only thing you need to do do is
echo ${(L)mapfile[file]}
or if you need the contents of a file or a fallback value in case the file doesn't exist, mapfile
should be the easiest way to go:
echo ${mapfile[file]:-Fallback value}
or if you need to do some initial search and replace:
echo ${mapfile[file]//search/replace}
Of course, you can also write the edited contents back to disk:
mapfile[file]=${mapfile[file]//search/replace}
No big deal. Another thing you could do is to get the length of a textfile in characters (i.e. bytes):
echo ${#mapfile[file]}
Whatever you want! You can also use mapfile
in combination with vared
to let the user edit files interactively:
vared mapfile[file]
Of course, you could also open some more advanced editor such as vim, but at least as a fallback, mapfile
in combination with vared
becomes a valuable tool because no external program is required.
You see, under some circumstances, mapfile
can really save your neck. But you should also be aware, that it may also consume a lot of memory, particularly with large files. So use it with caution.
Read more about mapfile: