4

While manually copying the file the following works, as below:

userx@x:~$ cp -rv /opt/test-bak/* /opt/test/
'/opt/test-bak/file1' -> '/opt/test/file1'
'/opt/test-bak/file2' -> '/opt/test/file2'
'/opt/test-bak/file3' -> '/opt/test/file3'
'/opt/test-bak/subdir1/subfile1' -> '/opt/test/subdir1/subfile1'
'/opt/test-bak/subdir2/subfile2' -> '/opt/test/subdir2/subfile2'

However, installing it as a system service returns the "cannot stat '/opt/test-bak/*': No such file or directory" error

● testcopy.service - test usage of /bin/cp in systemd
   Loaded: loaded (/etc/systemd/system/testcopy.service; disabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Sun 2019-04-21 14:55:16 +08; 4min 28s ago
  Process: 7872 ExecStart=/bin/cp -rv /opt/test-bak/* /opt/test/ (code=exited, status=1/FAILURE)
 Main PID: 7872 (code=exited, status=1/FAILURE)

Apr 21 14:55:15 userx@x systemd[1]: Started test usage of /bin/cp in systemd.
Apr 21 14:55:15 userx@x cp[7872]: /bin/cp: cannot stat '/opt/test-bak/*': No such file or directory
Apr 21 14:55:16 userx@x systemd[1]: testcopy.service: Main process exited, code=exited, status=1/FAILURE
Apr 21 14:55:16 userx@x systemd[1]: testcopy.service: Unit entered failed state.
Apr 21 14:55:16 userx@x systemd[1]: testcopy.service: Failed with result 'exit-code'.

My service file as below:

[Unit]
Description=test usage of /bin/cp in systemd

[Service]
Type=simple
ExecStart=/bin/cp -rv /opt/test-bak/* /opt/test/

[Install]
WantedBy=multi-user.target

Journal shows the below

Apr 21 15:05:12 x systemd[1]: Started test usage of /bin/cp in systemd.
Apr 21 15:05:12 x cp[9892]: /bin/cp: cannot stat '/opt/test-bak/*': No such file or directory
Apr 21 15:05:12 x systemd[1]: testcopy.service: Main process exited, code=exited, status=1/FAILURE
Apr 21 15:05:12 x systemd[1]: testcopy.service: Unit entered failed state.
Apr 21 15:05:12 x systemd[1]: testcopy.service: Failed with result 'exit-code'.

Can anyone shed some light on this?

  • You should set the type of service to oneshot as that type is only ensured not to already be running when started and not restarted when it exits. – Dan D. Apr 21 at 17:29
10

When using filename globbing patterns on the command line, it's the shell that expands the globbing patterns to filenames that match them, creating a list of pathnames that is then passed on to the utility that you are calling (cp here).

The command that you specify with ExecStart in your service file will not run in a shell. This means that the filename globbing pattern * will not be expanded and that cp will be called with /opt/test-bak/* as the single literal source path to copy.

You could try wrapping your command in an in-line shell script:

ExecStart=/bin/sh -c '/bin/cp -rv /opt/test-bak/* /opt/test/'

Or, wrap your command in a short shell script,

#!/bin/sh

/bin/cp -rv /opt/test-bak/* /opt/test/

and then call that instead.

Since I know virtually nothing about systemd, there may be better ways to do this though.

Note that if the * glob does not match anything (because the directory is empty), then you would have the same issue as before. An unmatched globbing pattern will by default be left unexpanded.

Personally, I would use either

cd /opt/test-bak && /bin/cp -Rp -v . /opt/test

or

rsync -ai /opt/test/bak-test/ /opt/test

Since neither of these rely on the shell doing filename generation, they could both run without a wrapping shell. Not relying on a shell glob would also, in this case, ensure that hidden files and directories in bak-test will get copied.

  • tested the first method, modifying to: ExecStart=/bin/sh -c '/bin/cp -rv /opt/test-bak/* /opt/test/' Works smoothly, thanks! – Koay Chiang Teik Apr 21 at 8:22
  • 1
    Related: unix.stackexchange.com/questions/216780/… – steve Apr 21 at 9:26
  • 1
    @steve Ok, so it has some very basic shell capabilities, but filename generation does not seem to be one of them. – Kusalananda Apr 21 at 9:31
  • For best results when running the command via a shell, exec the cp. Do not rely upon a shell doing this implicitly. Chain load dæmons, rather than leaving shell parent processes lying around. – JdeBP Apr 21 at 11:52
  • 1
    @kusalananda, I tested your version cp -rv /opt/test/bak-test/ /opt/test, which is not the intended outcome of this question, as it results in nesting the bak-test folder into the /opt/test folder. The example using rsync is a good option, thanks for pointing it out. I would have tried rsync next but I was stumped why cp wouldn't work even after triple checking everything. – Koay Chiang Teik Apr 21 at 12:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.