88

I'm trying to set up a simple systemd timer to run a bash script every day at midnight.

systemctl --user status backup.service fails and logs the following:

backup.service: Failed at step EXEC spawning /home/user/.scripts/backup.sh: No such file or directory.

backup.service: Main process exited, code=exited, status=203/EXEC
Failed to start backup.
backup.service: Unit entered failed state.
backup.service: Failed with result 'exit-code'.

I'm lost, since the files and directories exist. The script is executable and, just to check, I've even set permissions to 777.

Some background:

The backup.timer and backup.service unit files are located in /home/user/.config/systemd/user.

backup.timer is loaded and active, and currently waiting for midnight.

Here's what it looks like:

[Unit]
Description=Runs backup at 0000

[Timer]
OnCalendar=daily
Unit=backup.service

[Install]
WantedBy=multi-user.target

Here's backup.service:

[Unit]
Description=backup

[Service]
Type=oneshot
ExecStart=/home/user/.scripts/backup.sh

[Install]
WantedBy=multi-user.target

And lastly, this is a paraphrase of backup.sh:

#!/usr/env/bin bash

rsync -a --delete --quiet /home/user/directory/ /mnt/drive/directory-backup/

The script runs fine if I execute it myself.

Not sure if it matters, but I use fish as my shell (started from .bashrc).

I'm happy to post the full script if that's helpful.

dwrz
  • 2,991
  • 2
  • 10
  • 14
  • 4
    What does `ls -l /home/user/.scripts/backup.sh` output ? The start of your backup.sh script looks very strange: `#!/user/env/bin bash` , does the executable `/user/env/bin` actually exist ? Are you sure you didn't mean `/usr/bin/env` or `/home/user/bin/env` ? – nos Aug 19 '17 at 21:07
  • ```ls``` outputs ```-rwxrwxrwx 1 dwrz dwrz 1470 Aug 11 01:57 /home/user/.scripts/backup.sh```. And my apologies -- the typo in the shebang was when I was copying things over to here. It's ```/usr/``` in the script. – dwrz Aug 19 '17 at 23:36
  • Aside: Starting fish from `.bashrc` is a **really** bad idea. Update your `/etc/passwd` entry to directly specify fish, don't confuse programs that may intentionally want to run an interactive bash instance by making it start a different, incompatible shell instead. – Charles Duffy Aug 19 '17 at 23:41
  • As for the immediate issue at hand, I'd start by reproducing it with [Sysdig](http://sysdig.org/) tracing execution; that way you can find the exact syscall that fails and extract pertinent details (active PATH, uid, gid, etc). – Charles Duffy Aug 19 '17 at 23:43
  • BTW, **is** there a `PATH` set when your service is invoked? If `env bash` can't find `bash` because there's no `PATH`, that would cause your bug. Setting `Environment=PATH=/bin:/usr/bin` or otherwise a known-good value in the `.service` wouldn't hurt. – Charles Duffy Aug 19 '17 at 23:44
  • Thanks so much, Charles. I didn't set ```fish``` in ```/etc/passwd```, as the [Arch Wiki advises against it](https://wiki.archlinux.org/index.php/Fish), but I appreciate the head's up and will look into that as well. For now I tried two things: (1) specifying the ```PATH``` in the service file, (2) just using ```#!/bin/bash``` in the script (which still runs fine when I execute it myself). I'm still getting the same error with systemd (made sure to ```daemon-reload```). I'm going to look at ```sysdig``` now. – dwrz Aug 20 '17 at 00:24
  • Looking into /var/messages may reveal some more details about the failure. Also serverfault has some questions on this topic, see: https://serverfault.com/questions/957084/ – Attila Csipak Jul 29 '20 at 17:14

8 Answers8

195

I think I found the answer:

In the .service file, I needed to add /bin/bash before the path to the script.

For example, for backup.service:

ExecStart=/bin/bash /home/user/.scripts/backup.sh

As opposed to:

ExecStart=/home/user/.scripts/backup.sh

I'm not sure why. Perhaps fish. On the other hand, I have another script running for my email, and the service file seems to run fine without /bin/bash. It does use default.target instead multi-user.target, though.

Most of the tutorials I came across don't prepend /bin/bash, but I then saw this SO answer which had it, and figured it was worth a try.

The service file executes the script, and the timer is listed in systemctl --user list-timers, so hopefully this will work.

Update: I can confirm that everything is working now.

dwrz
  • 2,991
  • 2
  • 10
  • 14
  • 13
    This solved it for me. The reason it works with other scripts is that they have a shebang (#!/bin/bash) at the beginning while this particular one had not. – Felix Müller Apr 05 '18 at 15:17
  • this work around is super annoying, writing a `#!` line tells the kernel what interpreter to use, now I have to mirror this information in a unit file for applications that aren't singletons -_- what – ThorSummoner Apr 19 '18 at 19:38
  • 1
    Even when the executable is not a bash script, such as in my case, `jupyter` on CentOS 7, `/bin/bash -c "..."` is necessary. I think it is because it's a python script, and it has a shebang of python at the very beginning. – WesternGun May 31 '18 at 09:01
  • 1
    Scripts should have an interpreter, otherwise they're not a script. You should fix the script, rather than add bash to your `.service` file. – mikemaccana Dec 06 '18 at 13:37
  • 1
    Sometimes you need a `chmod +x /home/user/.scripts/backup.sh`. – ST-DDT Feb 21 '19 at 14:01
  • 1
    In my case I was missing .sh extension – nilesh May 06 '19 at 18:57
  • 1
    I had `#!/bin/bash` and it still didn't work. I don't know why, but `/bin/bash` prefix in `.service` file was still necessary – Slimer Jul 24 '19 at 06:54
  • I had a similar issue (nodejs file background process in my case) and had setup it like this... Works like a charm! Had to change the file rights to allow executing it though. – MrG Dec 11 '19 at 09:03
  • This is the only thing that worked for me - for some reason, the shebang line simply does not work at all with systemd (Ubuntu 18.04), despite all the comments saying to add it. Everything else was set correctly too - user, group, working directory, etc. – stormbeta Mar 22 '21 at 18:18
  • Well this worked, strange part is that the file had been working for months prior. Not sure why it wanted the update now. – The Thirsty Ape Aug 03 '21 at 23:58
  • new error : Main process exited, code=exited, status=243/n/a – Yogi Arif Widodo Aug 19 '22 at 20:31
  • 1
    RHEL-9 requires "/bin/bash" EVEN if the script executes fine from command-line – R.G. Mar 10 '23 at 18:59
18

To simplify, make sure to add a hash bang to the top of your ExecStart script, i.e.

#!/bin/bash

python -u alwayson.py    
crizCraig
  • 8,487
  • 6
  • 54
  • 53
10

When this happened to me it was because my script had DOS line endings, which always messes up the shebang line at the top of the script. I changed it to Unix line endings and it worked.

ke4ukz
  • 350
  • 3
  • 10
  • 3
    You saved my life! I just added `#!/usr/bin/env bash` at the first line of the `.sh` then worked. – kujiy Apr 23 '18 at 02:11
10

I ran across a Main process exited, code=exited, status=203/EXEC today as well and my bug was that I forgot to add the executable bit to the file.

Karl Pokus
  • 772
  • 1
  • 7
  • 14
  • 1
    I came here and read the marked answer and discovered before reading your answer that simply doing a chmod 700 – nikolaosinlight Nov 05 '20 at 00:50
8

If that is a copy/paste from your script, you've permuted this line:

#!/usr/env/bin bash

There's no #!/usr/env/bin, you meant #!/usr/bin/env.

Ivan Savcic
  • 194
  • 2
  • 7
  • 1
    Nice catch! The script is correct now, but it's possible I may have fixed it afterwards. It if it was a copy-paste, this would have explained it. – dwrz Mar 19 '19 at 00:17
3

try running:

systemctl daemon-reload

and then again run

service <yourservice> status
fccoelho
  • 6,012
  • 10
  • 55
  • 67
1

I faced a similar issue, changed the permission and added executable permission

use chmod +x /etc/systemd/system/<service-filename>

This worked for me

Rajeev
  • 119
  • 4
0

I actually used the answer from How do I run a node.js app as a background service? combined with what dwrz said above. In my case, I was creating a Discord bot that needed to be able to run when I was not around.

With this service in place, I initially got the same error that the initial poster did, which brought me here. I was missing the #!/usr/bin/env node at the top of my executed node.js script.

Since then, no problems, although I intend to see what else can be extended to the service itself.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Wirehead
  • 9
  • 2