systemd 和复制 (/bin/cp): 没有这样的文件或目录

systemd 和复制 (/bin/cp): 没有这样的文件或目录

手动复制文件时,以下工作有效,如下所示:

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'

但是,将其安装为系统服务会返回“cannot stat '/opt/test-bak/*':没有这样的文件或目录”错误

● 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'.

我的服务文件如下:

[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

日志显示如下

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'.

有人能解释一下吗?

答案1

在命令行上使用文件名通配模式时,shell 将通配模式扩展为与其匹配的文件名,创建路径名列表,然后将其传递给您正在调用的实用程序(cp此处)。

您在服务文件中指定的命令ExecStart不会在 shell 中运行。这意味着文件名通配模式*将不会扩展,并且将作为要复制的单个文字源路径进行调用cp/opt/test-bak/*

您可以尝试将命令包装在内联 shell 脚本中:

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

或者,将命令包装在一个简短的 shell 脚本中,

#!/bin/sh

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

然后调用它。

由于我对 systemd 几乎一无所知,因此可能有更好的方法来做到这一点。

请注意,如果*glob 不匹配任何内容(因为目录为空),那么您将遇到与以前相同的问题。默认情况下,不匹配的通配模式将不展开。

就我个人而言,我会使用

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

或者

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

由于它们都不依赖于 shell 来生成文件名,因此它们都可以在没有包装 shell 的情况下运行。在这种情况下,不依赖 shell glob 也可以确保隐藏的文件和目录bak-test被复制。

相关内容