This article is part of the 2011 Advent calendar series “24 Outstanding ZSH Gems”. Each day between December 1st and December 24th an article will be published as part of this series showing one awesome feature of the Z Shell. Some of the features can of course also be found in other shells such as Bash, but the ZSH implementation is often superior.

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.