X
Popular Searches

How to Run a Linux Command When a File Set Changes

Domino effect.
Shutterstock/Gecko Studio

Learn how to run Linux commands when any file in a watched set of files changes, and when new files are created. We show you how to use this flexible tool.

The entr Command

You can set commands to run at specific times in Linux, using cron. It’s easy, reliable, and flexible. But what if you need to have commands executed whenever a file changes, or if a new file is added to a directory? That’s possible, too, and there’s more than one way to do it. The entr command is a refreshingly straightforward way to achieve that functionality.

Some systems, such as the Hugo static site generator, have a feature that automatically rebuilds your website if a file changes, or if a new file is added to the site. That little feature makes a significant difference to your workflow. With Hugo, you’re able to have your development version of the website in your browser as you edit the files that make up your site. Each time you save your changes or create a file, the website is rebuilt in milliseconds, and the changes are pushed to your browser. Instant feedback is fantastic.

The entr command brings that type of capability to any set of files. The command that is launched when a change is detected is arbitrary. It can be a standard Linux command, an alias, a shell function, or a script.

Installing entr

To install entr on Ubuntu, use this command:

sudo apt-get install entr

sudo apt-get install entr in a terminal window

To install entr on Fedora, type:

sudo dnf install entr

sudo dnf install entr in a terminal window

On Manjaro, the command is:

sudo pacman -Syu entr

sudo pacman -Syu entr in a terminal window

A Simple Example

We’ll use the touch command to create a text file called “example.txt” and tell entr to monitor that file.

The entr command accepts the filenames it should monitor via STDIN and accepts the command it should run as command line parameters.

The easiest way to pass a filename to entr is to use ls to list it, and pipe that into entr. When the file changes, entr will launch wc command to count the lines, words, and characters in the file.

The /_ parameter is a placeholder for the filename of the file that was passed to entr. If a group of files is passed to entr, such as *.txt , the /_ parameter would be replaced by the last file to be changed.

touch example.txt
ls example.txt | entr wc /_

ls example.txt | entr wc /_ in a terminal window

Each time the changes are saved to the file, entr launches wc . To stop entr, hit q, or Ctrl+c .

RELATED: What Are stdin, stdout, and stderr on Linux?

Practical Uses

Now that we’ve seen entr in action and you understand the principle, let’s look at some more useful scenarios.

We’ll make entr monitor the files in the current directory. If any of the files are modified, we want entr to launch make for us to rebuild our project. We’ll chain another command, make test, to run some tests on the new build. The AND operator && will only launch the second command if the first completes without any issues.

The -s (shell) option makes sure that the interpreter used is the one defined in the SHELL environment variable. This ensures entr receives the exit code from the first make command.

ls | entr -s 'make && make test'

Using the ls command to send the list of all filenames in the directory to entr is a bit clunky. You might have files in the directory that are part of the project but are not actually build files. Perhaps they are design notes or a to-do list. You don’t need to have your project rebuilt every time you change one of those non-code files.

We can refine the command so that it monitors only the appropriate source code files. This command monitors the C source code and header files.

ls *.[ch] | entr -s 'make && make test'

Of course, we’re not limited to launching make. You might have a custom build script that you’d prefer to use.

ls *.[ch] | entr script.sh

Leveraging Git

The entr command isn’t Git-ware, but we can still use some of Git’s capabilities to smooth our workflow.

The git ls-file command will list the files that are in Git’s index and working source tree, taking into account the exceptions that have been defined in your “.gitignore” file. That’s a ready-made list of the files that we’re interested in, so let’s use that as the source of the files to monitor.

git ls-files | entr script.sh

The ls-files command accepts command-line options. These can be used to further filter or augment the files list returned by Git:

  • -c: Show cached files.
  • -d: Show deleted files.
  • -m: Show modified files.
  • -o: Show untracked files.

The --exclude-standard option is a shorthand way to tell Git to ignore files that match the entries in the “.git/info/exclude”, local “.gitignore”, and global “.gitignore” files.

git ls-files -cdmo --exclude-standard | entr 'make && make test'

That’ll catch a lot of eventualities, but it won’t cope with a new file being created. And the new file won’t be in Git. We can still cope with that situation, using a little bit of Bash scripting and a feature of entr.

The -d (directory) option causes entr to monitor the files in a directory and to exit if a new file is added. By wrapping our entr command in a while/do loop, the entire entr command line will be automatically restarted, and the new file will be picked up and acted upon. Files and directories whose names start with a period “.” are ignored.

while true; do

  { git ls-files; git ls-files . --exclude-standard --others; } | entr -d ./script.sh

done

Restarting Servers and Interpreters

Perhaps you work with an interpreted language like Ruby. Each time your program file is changed, you need to stop and restart the Ruby interpreter. You can handle these types of use cases with the -r (restart) option.

To monitor a program file called “hello_world.rb”, and to stop and restart the Ruby interpreter each time the program file changes, use this command:

ls hello_world.rb | entr -r ruby hello_world.rb

Each time the program file is edited and saved, the Ruby interpreter is restarted and the program reloaded.

ls hello_world.rb | entr -r ruby hello_world.rb in a terminal window

The program initially contained:

puts "Hello, World!"

It was edited to say:

puts "Hello, CloudSavvyIT!"

When this was saved, entr restarted the Ruby interpreter, and reloaded the program.

The file was edited once more to add the word “readers” and saved to the hard drive.

puts "Hello, CloudSavvyIT readers!"

You can see the three outputs in the screenshot. If you press the spacebar, entr will restart the command whether you’ve changed the program file or not.

Not Just for Programmers

Because the command launched by entr can be anything, including shell scripts, the scope for using entr to automate processes is virtually limitless.

Perhaps you have a directory that has files dropped into it by secure FTP, or rsync, or curl. You could have these files automatically copied somewhere else, or compressed, or searched by grep for the word “error”.

This makes it a great tool for system administrators and developers alike.

Dave McKay Dave McKay
Dave McKay first used computers in the industry when punched paper tape was in vogue and he has been programming ever since. His use of computers pre-dates the birth of the PC and the public release of Unix. He has programmed in everything from 6502 assembly to Lisp, and from Forth to C#. He is now a technology journalist and independent Data Protection and Compliance consultant. Read Full Bio »

The above article may contain affiliate links, which help support CloudSavvy IT.