手动复制文件时,以下工作有效,如下所示:
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
被复制。