This chapter is about how
fswatch is invoked. There are
many options and two styles for writing them.
fswatch is invoked using the following syntax:
fswatch (options)* (paths)+
fswatch interprets file names as being relative to the
working directory and canonicalizes them using
If a directory is used as an argument, the directory object is watched and, optionally and depending on the monitor being used, the directory is scanned recursively and all its children are watched as well.
Depending on the monitor being used, recursively scanning huge directory hierarchies or big set of files may be resource consuming, CPU intensive or even impossible. The characteristics of the available monitors in a system should be assessed in order to choose the best monitor according to the specific needs.
Besides successful exits4, indicated with the exit
fswatch may exit with an error.
will try to print a diagnostic description on
stderr when an
unexpected error occurs.
The documented5 exit codes of
fswatch are the
FSW_EXIT_OK: No error occurred.
FSW_EXIT_UNK_OPT: An unknown option was input.
FSW_EXIT_USAGE: Help message was requested.
FSW_EXIT_LATENCY: Invalid latency.
FSW_EXIT_STREAM: A stream related problem occurred.
FSW_EXIT_ERROR: An unkown error occurred.
FSW_EXIT_ENFILE: A file could not be opened.
FSW_EXIT_MONITOR_NAME: The specified monitor does not exist.
FSW_EXIT_FORMAT: The specified monitor is invalid.
fswatch implements two option styles which are common in
Unix and Unix-like operating systems and GNU software: short
and long options. The biggest difference between short and
long options are argument placing (for options taking one).
Whether long options are available in a system depend on the
availability of the
getopt_long function at build time. For
this reason, users should familiarise themselves with short options
and use them when possible and do not rely on long options to be
available on any
In systems where the
getopt_long function is available, each
short option has a corresponding long option with a mnemonic
name starting with two dashes (e.g.: --version). Long
options are meant to be easy to remember and to provide hints about
what a command is going to perform. The following command:
$ fswatch --event-flags --numeric --recursive ~
is clearer than:
$ fswatch -xnr ~
If a long option takes an argument, it can be specified in two ways, depending on whether the argument is optional or mandatory:
$ fswatch --latency=5 ~
$ fswatch --latency 5 ~
Most options have a short form consisting of a dash followed by a single character, such as -l (which is equivalent to --latency). When available, a short form is interchangeable with the long one.
If a short option takes an argument, it can be specified in two ways:
$ fswatch -l 5 ~
$ fswatch -l5 ~
Short options can be stuck together provided all the options but the last one take no argument, in which case it can be specified as described above. The command:
$ fswatch -xnrl 5 ~
is equivalent to:
$ fswatch -x -n -r -l 5 ~
where ‘5’ is the argument of -l.
In the following table you can find the list, in alphabetical order,
Monitor file access. This functionality is supported by selected monitors only.
Sets the allow overflow flag of the monitor. When this flag is set,
monitor buffer overflows are reported as change events of type
Print a marker at the end of every batch.
Request the monitor to watch directories only during a recursive scan. This feature helps reducing the number of open file descriptors if a generic change event for a directory is acceptable instead of events on directory children.
Filter events by type using the specified event name or numeric mask (see Filtering by Event Type). Specified event names are included in the output. Multiple event types can be specified using this option multiple times.
Print the event flags.
Use the specified string as event flag separator.
Exclude paths matching
Use extended regular expressions.
Load filters from the specified
Fire idle events.
Symbolic links are followed instead of being watched as file system objects.
Use the specified record format.
Print the event time using the specified
Show the help message.
Include paths matching
Use case insensitive regular expressions.
Set the latency using the specified
List the available monitors.
Use the specified
Pass the specified property to the monitor (see Monitor Tunables).
Print a numeric event mask.
Print a single message with the number of change events in the current batch.
fswatch after the first set of events is received.
Use the ASCII ‘NUL’ (‘\0’) as record separator.
Print the event timestamp.
Print the event time as UTC time.
Print verbose output.
Print the version of fswatch and exit.
As seen in Observing File System Changes, file names may contain
characters such as ‘\n’ which are commonly used as line
separators. Many commonly used Unix commands and shell builtins use
characters in the
separators to split words. By default,
$IFS contains the
characters ‘ ’ (SPC), ‘\t’, ‘\n’ and ‘\0’
Therefore, if a file contains such a separator character (and all but ‘NUL’ are legal), then a parsing ambiguity may arise when using certain record formats such as:
In this case, for example, if n > 1 flags are present in the record, and hence more than one ‘ ’ (SPC) is present, then it is not known whether any subset containing a number x of consecutive flags (x < n) is part of the path or not.
The same reasoning applies when splitting lines instead of words: since ‘\n’ may be a legal file name character, then it is now known whether ‘\n’ indicates a record’s end or simply is part of a file name.
For this reason, in order to avoid parsing ambiguity, this options
fswatch to use ASCII ‘NUL’ as
Warning: The use of the --print0 solves the line splitting ambiguity but not the word splitting ambiguity when using textual event flags. A solution to this problem is provided by custom record formats (see Custom Record Formats).
Another way to get an unambiguous record format is using numeric event flags (see Numeric Event Flags).
To solve the problem of line splitting ambiguities and to provide
users the possibilities of tailoring the record format to their needs,
fswatch allows users to specify the event record
format using the --format option.
This options requires a
format string ordinary text containing zero or more
directives. Characters not belonging to a format directive are
copied unchanged to the output, while directives are interpreted and
replaced with the result of their evaluation.
Directives start with ‘%’ which is always treated as a special character: either it marks the beginning of a directive or it is interpreted as an escape character8.
The available directives are:
Inserts the ‘%’ character.
Inserts an ASCII ‘NUL’ (‘0’) character.
Inserts a newline character.
Inserts the list of event flags, separated by default by the space character (‘ ’) or by the separator specified with the --event-flag-separator option (see Event Flag Separator).
Inserts the path.
Inserts the timestamp, formatted with
strftime using the
format optionally specified with the --format-time option.
Each record is terminated by either a newline character (‘\n’) or an ASCII ‘NUL’ character when -0 is specified. The record termination character has the following characteristics:
When the list of event flags is printed, textual items are separated by default by spaces (‘ ’). The user can specify an alternate event flag separator using the --event-flag-separator and passing the desired separator string as argument.
For instance, if the user wants event flags to be separated by a comma, the following command can be used:
$ fswatch --event-flag-separator=, -x (options)* (paths)+
The format used by
fswatch when a custom format is not
specified is determined as follows9:
fswatch typically outputs an endless event
stream, processing parties parsing its output may be interested in
‘batch event processing’: that is, processing batches of events
instead of endlessly processing events one by one.
To support this use case,
fswatch provides the
--batch-marker option; when specified,
output a customizable ‘batch marker record’ processing parties can use
as batch delimiters. Batch demarcation is made naturally using
the monitor’s processing loop and its latency setting: every time the
monitor loops (typically when latency is elapsed), then a batch marker
is printed as final record, as shown in the next example:
$ fswatch --batch-marker -r ~ /home/fswatch/.zsh_history.LOCK NoOp /home/fswatch/.zsh_history.new /home/fswatch/.zsh_history /home/fswatch/.zsh_history.LOCK NoOp
By default, the batch marker takes the form of a single-line record:
NoOp(\n | \0)
terminated with either ‘\n’ or ‘NUL’ (‘\0’) depending
fswatch settings. However, the user can customize
it by providing the desired marker string as optional argument to
% ./fswatch --batch-marker="*** BATCH END ***" -r ~ /home/fswatch/.zsh_history.LOCK *** BATCH END ***
An idle event is a special event type that can optionally be
fswatch if no change events were collected in a
period of time whose average length is equal to the monitor latency
(see Latency). Idle events come in handy when an observer wants
to perform an operation every time a change is detected or
after a specified amount of time even if no changes were detected.
Idle events were introduced in version 1.9.0 and are available only
fswatch is built on a platform that supports C++11
std::thread) and can be enabled using the
An idle event has got the following characteristics:
Filters are regular expression which are evaluated against the monitored object path to determine whether a path must be accepted or rejected. Sometimes, the exclusion of a path may result in the exclusion of an object from the list of monitored objects, while other times a path must be evaluated only when an event is detected and in this case the corresponding object cannot be removed from the monitored object list in advance10.
Event though event filtering is commonly performed when
fswatch output, the possibility of filtering
paths ‘at the source’ provides not only a greater amount of
flexbility, but also:
fswatchwill only monitor matching objects11.
Since filters are implemented using the ‘regcomp’ library, this
feature is built into
fswatch only on systems where this
library is available.
Path filters can be specified in two ways:
The filter file is made up of records separated by a new line charactere, or formally a ASCII ‘LF’ (line feed) character. The structure of the record is the following:
where ‘type’ indicated the filter type and ‘pattern’ is the filter regular expression. ‘type’ may contain the following characters:
The following filter file instructs
fswatch to ignore all
files except those ending in ‘.cpp’, ignoring case.
- .* +i \.cpp$
Two types of filters are available:
As their name indicates, they are used to include and exclude paths
from the monitored object list and from resulting events.
fswatch processes filters this way:
Said another way:
Filters are regular expression executed using the
regcomp function which is able to interpret case-sensitive
and case-insensitive basic and extended regular
expressions as described in
Base Definitions volume of IEEE Std 1003.1-2001,
Chapter 9, Regular Expressions.
The (--insensitive, -I) option instructs
fswatch to use case insensitive regular expressions. The
following example adds an exclusion filter so that
ignores any file system object whose name ends with .log, no
matter the case.
$ fswatch -Ie ".*\.log$" ~
The (--extended, -E) option instructs
fswatch to use extended regular expressions, such as:
$ fswatch -Ee "xl[st]+" ~
Treating the characteristics and the difference between different kinds of regular expressions is out of scope in this manual.
Events can be filtered by event type passing
fswatch a list of
event type names or masks to accept using the --event
$ fswatch -x --event Created --event Removed ~ $ fswatch -x --event 10 ~
In this example, the mask of the
Created event is
and the mask of the
Removed event is
8, so the mask
of both events is
If no event type filters are specified,
fswatch will accept
events of any type; on the other hand, as soon as a filter is specified,
only events with a matching type will be accepted.
The latency l, expressed in seconds, is the amount of
time that passes between the moment
fswatch outputs a set of
detected changes and the next. What happens during the time
in-between is a monitor-specific implementation detail.
Some APIs, such as OS X’s FSEvents, implement the concept of
latency themselves and
fswatch appears idle in between.
Only when the specified amount of time passes, change events are
received, processed and written to standard output. Others, such as
Linux’s inotify, do not12; in this case, the inotify monitor waits
for events a maximum of l seconds; after that, the monitor
logic loops again, performs house-keeping activities13
and starts waiting again.
The important thing to keep in mind is that latency and a monitor’s behaviour are implementation-dependent: check the documentation of the monitor you are using to get further information about how latency is handled.
Symbolic links are commonly used file system objects and, as it is
customary for file system utilities,
fswatch can either
follow them and monitor the linked object14 or monitor the link
Event flags identify the kind of change a file system object has undergone. Many of them directly map to common file system operations (such as creation, deletion, update, etc.), others are less common (such as attribute modification), and others are monitor and platform specific.
fswatch maps monitor-specific event flags to
‘global’ event flags acting as a sort of ‘greatest common denominator’
of all the available monitor flags. The list of all the available
global event flags, defined in c/cevent.h, is the following:
Idle event, optionally issued when no changes were detected.
This event maps a platform-specific event that has no corresponding flag.
The object has been created.
The object has been updated. The kind of update is monitor-dependent.
The object has been removed.
The object has been renamed.
The object’s owner has changed.
An object’s attribute has changed.
The object has moved from this location to a new location of the same file system.
The object has moved from another location in the same file system into this location.
The object is a regular file.
The object is a directory.
The object is a symbolic link.
The object link count has changed.
The monitor has overflowed.
As you can see, the list of event flags contains element whose meaning
is overlapping, at least partially.
Link, for instance, may
be equivalent to
Removed, depending on
the whether the new link count is 1 or 0.
MovedTo may be equivalent to
Removed if the monitor is unable to discern a move operation
has taken place (which is not always possible, as in the case of the
fswatch is unable to univocally map the specific flags of
all the monitors consistently. Forcefully, the mapping depends on the
capabilities of the monitor which, in turn, depend on the capabilities
of the API being used.
For this reason, when processing change events, either the behaviour of the underlying monitor is known and taken into account, or all the flags which could possibly be attached at the operation being looked for must be taken into account.
Warning: As already explained (see Whitespace and Record Format), the record format when using event flags in textual form is ambiguous. For this reason, using numeric event flags (see Numeric Event Flags) or a custom record format (see Custom Record Formats) is recommended when
fswatchoutput must be processed.
When using the (--numeric, -n)
will output event flags in numeric format. A change event
record may have multiple event flags and the numeric value is
calculated as the bitwise
or of the numeric values of all
the flags. Since the value of an event flag is guaranteed to be
unique and to be a number n in the form n = 2^k for a
certain integer k, then the numeric value of a set of event
flags is univocally determined.
To check whether a given event flag is present when processing
fswatch output, iti s sufficient to check whether its bit is
set to 1 in the event value. Let’s suppose we want to check whether
the event flag whose value is e is present in a record whose
flag numerical value is n. If the result r of
where \wedge is the bitwise
and operator, is r
> 0, then the flag e is present in n.
The numeric value of all the event flags is the following:
fswatch is a front-end to multiple monitors, each
taking advantage of different monitoring APIs that may be
available in a system. When building
configure scans the system to check which APIs are
available and builds support for all of them.
A ‘special’ monitor, the poll monitor, manually scans the file
system looking for differences. This is a fallback monitor for
situations where other, more efficient APIs are not
available. The poll monitor is available on any system providing the
fswatch chooses the ‘best’ monitor between the
available ones, a user may wish to use another. A specific monitor
can be chosen using the (--monitor, -m) option. The
list of available monitors can be obtained using the
(--list-monitors, -M) option or at the end of the
$ fswatch --list-monitors fsevents_monitor kqueue_monitor poll_monitor
$ fswatch --help [...] Available monitors in this platform: fsevents_monitor kqueue_monitor poll_monitor [...]
A monitor can then be chosen by passing the mandatory ‘name’ argument to the -m option:
$ fswatch -m kqueue_monitor ~
In this case, the ‘kqueue_monitor’ is manually chosen.
fswatch’s behaviour when scanning a directory may vary on a
monitor by monitor basis. The semantics of the (--recursive,
-r) option is: recursively scan subdirectories. However,
implementations may silently add ‘if the monitor does not do so
already’. Since each monitor uses a different API, its
behaviour depends on that of the backing API, and it is
fswatchwill walk the file system hierarchy rooted at the directory and will open a file descriptor for each children to establish a watch on it.
ReadDirectoryChangesWAPI returns change events for first-level children of a directory. When the -r option is not specified, change events for a watched directory’s children are received. When the -r is specified, the monitor will walk the file system hierarchy rooted at the watched directory and will establish a watch on every directory object found.
In general, users should always use the -r option according to its semantics, no matter what the monitor does. The only case when -r is ‘not’ honoured is when a monitor adds information by recursively monitoring children even when -r is not specified. Please notice that when this happens, there may be no performance overhead since the backing API is specifically designed to behave like this.
The authors think this is not a problem. If you think this behaviour can be improved, please fill a bug report (see Reporting Bugs and Suggestions).
Some monitors such as the kqueue monitor require a file
descriptor to be open for each watched file system object. This
imposes a limitation on the maximum number of files that can be
fswatch. Before version 1.7, a user could only
overcome this problem by increasing the maximum number of open file
handles on its system.
fswatch 1.7.0 introduced a new option,
-d/--directories; when this option is used with a
monitor that supports it, only directory objects will be watched
during recursive scans. When a change occurs on a file, instead of
reporting which file has changed and how,
will report a change event on the parent directory: this way, the
number of required open file handles decreases at the expense of
change event information granularity.
Some monitors may accept monitor-specific parameters to tune their
behaviour. To this purpose,
fswatch offers a mechanism to
pass key-value pair which are literally passed to the underlying
monitor. A key-value pair
(k, v) can be passed to a monitor
$ fswatch --monitor-property k=v ~
Multiple key-value pairs can be passed by using the
--monitor-property option multiple times.
Depending on the monitor and options
fswatch may not exit unless stopped with
a signal such as
Exit codes are documented in c/error.h
IFS (Internal Field Separators).
available directive are much less than what
Which is the same as considering escaped characters the result of a directive.
In the following example, the record termination character is not shown.
This behaviour is monitor-specific.
Whether an object whose path is matched by an exclusion filter is monitored or not is a monitor-specific implementation detail.
inotify publishes changes on a file
identified by a descriptor which is
Such as re-scanning objects which did not exist in the previous iteration.
When following links, the resolution is recursive: that is, if a link points to another symbolic link, this link is followed as well, and so on, until an object of a different kind is found.
manually filtering out events based on paths, but
does not do so by design.