I am trying to set up a systemd timer to regularly backup a directory using the rsync command. I made an rsync command that works when run manually in a terminal, but it doesn't work correctly when run as a systemd timer.

detailed explanation:

As a simple example, I have following directory tree in /home/trevor/test_dir/:


I want to use rsync to copy this directory to my SSD for backup (mounted at /my_ssd/). But I want to exclude the directories dir_a and dir_b. So I run the command

rsync -a --exclude={/dir_a,/dir_b} /home/trevor/test_dir/ /my_ssd/test_dir/

This command works when I run it from a terminal: it excludes the directories dir_a and dir_b, but keeps dir_c.

Next, I try to make a systemd service and timer to run that command routinely (note that I determined the following steps mostly from the systemd/Timers page on the Arch Linux Wiki). I make the following service file


Description=systemd backup test

ExecStart=rsync -a --exclude={/dir_a,/dir_b} /home/trevor/test_dir/ /my_ssd/test_dir/

and the following timer file which will run the command every 30 seconds (for example)


Description=systemd backup test timer



I start the timer using systemctl start backup_test.timer. The timer does run every 30 seconds, but the "exclude" part seems to be ignored, and the entire directory is copied.

debugging attempts:

I tried the rsync command with multiple --exclude options instead of the brace expansion, in other words I used --exclude=/dir_a --exclude=/dir_b instead of --exclude={/dir_a,/dir_b}. This actually made the command work. So I think the problem is that the brace expansion is not being done properly.

Next, I tried to test a simpler command with brace expansion, to see if the brace expansion itself was the problem. So I replaced the rsync command in the systemd service with touch /home/trevor/test{1,2}.txt. This command created a file literally named /home/trevor/test{1,2}.txt. So I'm pretty sure the problem is that the brace expansion is not handled correctly by the systemd service.

1 Answer 1


I think I figured this out on my own by reading the manual for systemd services (man systemd.service). The ExecStart= option doesn't directly support shell command lines, which I think is why the brace expansion was not being performed as intended. I got everything to work by passing my rsync command to sh -c in the ExecStart= line:

ExecStart=sh -c 'rsync -a --exclude={/dir_a,/dir_b} /home/trevor/test_dir/ /my_ssd/test_dir/'


$ man systemd.service
       Note that shell command lines are not directly supported. If shell
       command lines are to be used, they need to be passed explicitly to a
       shell implementation of some kind. Example:

           ExecStart=sh -c 'dmesg | tac'
  • Another alternative is to just expand the list of excluded directories yourself: --exclude=/dir_a --exclude=/dir_b. You can also use a file with an exclude list for rsync, which should also work.
    – filbranden
    Feb 13, 2020 at 4:57
  • 1
    Thanks, I didn't know about the file option. Just to make note, that is the --exclude-from=FILE option.
    – Trevor
    Feb 20, 2020 at 0:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .