Next: Invoking fswatch
, Previous: Introduction, Up: Top [Contents][Index]
fswatch
This chapter is a tutorial walk-through on the most common use cases
where fswatch
is useful:
fswatch
output.
A common use case is detecting file system changes in a set of
file system objects1 where details of a
change are irrelevant. This mode of operation is called bulk
mode and fswatch
will only dump a single event record per
batch2 containing the number of affected file system
objects. No other details are avaible in the event record.
The most common application of this mode of operation is performing a
bulk action on all the observed file system objects, such as a
synchronization with rsync
, which will serve us as an
example. In this case, the detection of a change triggers the
execution of a synchronization script, no matter its kind nor the
specific object the event affects.
To run fswatch
in batch mode, the (-o,
--one-per-batch) must be used:
$ fswatch -o path ... 2 10
The (-l, --latency) option can be used to set the latency according to the requirements:
$ fswatch -o -l 5 path ... 4 7
This way, you can respond to change events in a way which is (or can easily be) path-independent (because you are not receiving any event detail) and you prefer to ‘bubble’ events together to reduce the overhead of the command being executed.
In bulk mode the output of fswatch
is guaranteed to have the
following structure:
number\n
where ‘number’ is an integer value and ‘\n’ is the new line
character. A line with this structure is very easy to read with
either xargs
or the read
builtin:
$ fswatch -o path | while read num ; \ do \ ... \ done
In many scripts of this kind, the num variable can even be ignored.
Besides the batch mode, fswatch
provides a main mode
providing full details of the kind of events detected and the file
system objects they refer to. The main mode is fswatch
’s
default mode of operation and needs no specific flags to be activated.
In this mode, fswatch
outputs change events to the standard
output. By default, only the affected file name is printed and the
change event record structure has the following structure:
/full/path/to/changed/object\n
However, many options are available to format the event record, including:
printf
-like format string.
Since a Unix file name may contain any character but the path
separator ‘/’ and ‘NUL’3 the choice of using ‘\n’ as record
separator may lead to unexpected results (since a file name can
legally contain ‘\n’).
For this reason, along the line of what other tools such as
find
and xargs
already do, the ‘NUL’
character (‘\0’) can alternatively be used:
/full/path/to/changed/object\0
Beside the full path of the change object, details on the kind of change event can be obtained using the (-x, --event-flags) option:
$ fswatch -xr /path/to/observe /path/to/observe Created Renamed OwnerModified IsFile ...
In this case, a space-separated list of change flags are printed after the path of the changed object. The record structure is thus:
/full/path/to/changed/object flag ([ ][flag])*
where ‘flag’ is an event flag. At least one event flag is always present, and additional ones are ‘bubbled’ into the same record and separated by space. For more information on event flags see Event Flags.
Since a file name may contain spaces, this record structure is not unambigually parseable if more than one event flag is present: in this case, any subset [0, x], x < n - 1 of the n event flags may be part or the file name and hence any parse result would be indeterminate. This issue can be solved using a custom record format (see Custom Record Formats).
Instead of using user-friendly event flag names, as seen in the previous section, numeric event flags can be used instead. Currently, the real advantage this method offers, despite possibly cleaner flag-decoding logic, is the availability of a non-ambigous event record representation.
To instruct fswatch
to print numeric event flags, the
(-n, --numeric) option must be used:
$ fswatch -xnr /path/to/observe /path/to/observe 2058
The numeric event flag value is the bitwise OR of the individual event flag values, that are powers of 2. In the previous example, the flag 2058 is decomposed in powers of 2 as 2058 = 2048 + 8 + 2 = 2^{11} + 2^3 + 2, that is, the eleventh, the third and the first event flags.
fswatch
OutputVery often you wish to not only receive an event, but react to it.
The simplest way to do it is piping fswatch output to another process.
Since in Unix and Unix-like file system file names may potentially
contain any character but ‘NUL’ (‘\0’) and the path
separator (‘/’), fswatch
has a specific mode of
operation when its output must be piped to another process. When the
(-0, --print0) option is used, fswatch
will use the ‘NUL’ character as record separator, thus allowing
any other character to appear in a path.
This is important because many commands and shell builtins (such as
read
) split words and lines by default using the characters
in $IFS
, which by default contains characters which may be
present (although rarely) in a file name, resulting in a wrong event
path being received and processed.
The simplest way to pipe fswatch
to another program is using
xargs
:
$ fswatch -0 [opts] [paths] | xargs -0 -n 1 -I {} command
The command in this example does the following:
fswatch -0
will split records using the ‘NUL’
character.
xargs -0
will split records using the ‘NUL’ character.
This is required to correctly match impedance with fswatch
.
xargs -n 1
will invoke command
every record.
If you want to do it every x
records, then use
xargs -n x
.
xargs -I {}
will substitute occurrences of {}
in command with the parsed argument. If the command you are running
does not need the event path name, just delete this option. If you
prefer using another replacement string, substitute {}
with your choice.
If a process or script is piped to fswatch
output, sometimes
it would be desirable to detect the ‘boundaries’ of a batch of
changes. This way, the process receiving the stream of changes would
rely on the timings imposed by the latency settings of
fswatch
to start a phase of events processing after a
phase or events gathering. The --batch-marker option
can be used to accomplish this task:
$ fswatch --batch-marker -r ~ /Users/enricomariacrisostomo/.zsh_history.LOCK NoOp /Users/enricomariacrisostomo/.zsh_history.new /Users/enricomariacrisostomo/.zsh_history /Users/enricomariacrisostomo/.zsh_history.LOCK NoOp
In this example, the ‘NoOp’ records mark the end of the 1 second
batches of events output by fswatch
. The batch marker can
be customized. For more information Batch Marker.
Another requested feature is the possibility of receiving a single
event and exit fswatch
. This is most useful when existing
scripts processing events include the restart logic of
fswatch
. This use case is implemented by the -1,
--one-event option:
$ fswatch -1 /path/to/watch /path/to/watch/child0 /path/to/watch/child1 ... $
In the context of this manual (unless specified otherwise), file system object refers undistinctively to files and directories.
A batch is an iteration of fswatch
scanning logic, whose frequency is \nu = l^{-1}, where l
is the latency.
Depending on the file system being used, other restrictions may apply. However, for file system portability reasons, you should consider ‘NUL’ as the only forbidden character.
Next: Invoking fswatch
, Previous: Introduction, Up: Top [Contents][Index]