rsync 从 shell 成功,但从 crontab 抱怨 "syntax or usage error"
rsync succeeds from the shell but complains of "syntax or usage error" from crontab
以下 crontab 行(在 CentOS 7.6 上)
@daily rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
失败,并向我发送以下电子邮件:
From: (Cron Daemon) <crontab@docker.local>
Subject: Cron <qa@docker> rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
rsync: failed to open files-from file <(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} ;): No such file or directory
rsync error: syntax or usage error (code 1) at main.c(1567) [client=3.1.2]
我查看了rsync的main.c的源代码,但是看不到1567行的相关性:
1557 SIGACTMASK(SIGINT, sig_int);
1558 SIGACTMASK(SIGHUP, sig_int);
1559 SIGACTMASK(SIGTERM, sig_int);
1560 #if defined HAVE_SIGACTION && HAVE_SIGPROCMASK
1561 sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
1562 #endif
1563
1564 /* Ignore SIGPIPE; we consistently check error codes and will
1565 * see the EPIPE. */
1566 SIGACTION(SIGPIPE, SIG_IGN);
1567 #ifdef SIGXFSZ
1568 SIGACTION(SIGXFSZ, SIG_IGN);
1569 #endif
1570
1571 /* Initialize change_dir() here because on some old systems getcwd
1572 * (implemented by forking "pwd" and reading its output) doesn't
1573 * work when there are other child processes. Also, on all systems
1574 * that implement getcwd that way "pwd" can't be found after chroot. */
1575 change_dir(NULL, CD_NORMAL);
1576
1577 init_flist();
此外,当我 运行 来自 shell 的确切 crontab 行时,它起作用了:
qa@docker /tmp$ rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
sending incremental file list
sent 18 bytes received 12 bytes 20.00 bytes/sec
total size is 0 speedup is 0.00
qa@docker /tmp$
关于如何调试这个问题有什么想法吗?
中断的 cron 作业通常是由于在不同于一个 cron 使用的 shell 中测试命令造成的。大多数流行的交互式 shells,如 bash
和 zsh
以及标准 /bin/sh
(由 cron 使用)具有相似的基本语法,因为它们都是 Bourne 的后裔shell。它们之间的相似性非常强,您可以暂时认为 cron 的命令语法与您的登录相同 shell.
当您将更复杂的命令放入 crontab 时,您会发现它们之间存在差异。在您的示例中,我怀疑命令替换运算符 <(...)
。这种类型的替换在 Bourne shell 中不存在,我认为 POSIX 也没有采用它,所以我不会在 cron 作业中信任它。
在您的系统上 /bin/sh
中测试您的命令,只需 运行 在您的另一个中 shell:
BIG-FANCY-PROMPT%>$ sh
$ rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
... probably some error message here...
$ exit
BIG-FANCY-PROMPT%>$ _
如果你想不出用 sh
语法重写命令的方法,你总是可以显式调用 bash
或你喜欢的任何其他 shell:
@daily bash -c '...'
这种方式涉及额外的引用层,因此 sh
会将整个命令传递给 bash
而无需尝试解析它。如果这变得太困难,那么将你的命令放在一个脚本中,其中包含一个漂亮的 #!
行和 运行 that 来自 cron.
以下 crontab 行(在 CentOS 7.6 上)
@daily rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
失败,并向我发送以下电子邮件:
From: (Cron Daemon) <crontab@docker.local>
Subject: Cron <qa@docker> rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
rsync: failed to open files-from file <(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} ;): No such file or directory
rsync error: syntax or usage error (code 1) at main.c(1567) [client=3.1.2]
我查看了rsync的main.c的源代码,但是看不到1567行的相关性:
1557 SIGACTMASK(SIGINT, sig_int);
1558 SIGACTMASK(SIGHUP, sig_int);
1559 SIGACTMASK(SIGTERM, sig_int);
1560 #if defined HAVE_SIGACTION && HAVE_SIGPROCMASK
1561 sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
1562 #endif
1563
1564 /* Ignore SIGPIPE; we consistently check error codes and will
1565 * see the EPIPE. */
1566 SIGACTION(SIGPIPE, SIG_IGN);
1567 #ifdef SIGXFSZ
1568 SIGACTION(SIGXFSZ, SIG_IGN);
1569 #endif
1570
1571 /* Initialize change_dir() here because on some old systems getcwd
1572 * (implemented by forking "pwd" and reading its output) doesn't
1573 * work when there are other child processes. Also, on all systems
1574 * that implement getcwd that way "pwd" can't be found after chroot. */
1575 change_dir(NULL, CD_NORMAL);
1576
1577 init_flist();
此外,当我 运行 来自 shell 的确切 crontab 行时,它起作用了:
qa@docker /tmp$ rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
sending incremental file list
sent 18 bytes received 12 bytes 20.00 bytes/sec
total size is 0 speedup is 0.00
qa@docker /tmp$
关于如何调试这个问题有什么想法吗?
中断的 cron 作业通常是由于在不同于一个 cron 使用的 shell 中测试命令造成的。大多数流行的交互式 shells,如 bash
和 zsh
以及标准 /bin/sh
(由 cron 使用)具有相似的基本语法,因为它们都是 Bourne 的后裔shell。它们之间的相似性非常强,您可以暂时认为 cron 的命令语法与您的登录相同 shell.
当您将更复杂的命令放入 crontab 时,您会发现它们之间存在差异。在您的示例中,我怀疑命令替换运算符 <(...)
。这种类型的替换在 Bourne shell 中不存在,我认为 POSIX 也没有采用它,所以我不会在 cron 作业中信任它。
在您的系统上 /bin/sh
中测试您的命令,只需 运行 在您的另一个中 shell:
BIG-FANCY-PROMPT%>$ sh
$ rsync -rav --remove-source-files --files-from=<(find /home/qa/buildbot/master/packages/rhel7 -type f -mtime +30 -exec basename {} \;) /home/qa/buildbot/master/packages/rhel7 192.168.1.31:/local/raid0/buildbotpackages/packages/rhel7
... probably some error message here...
$ exit
BIG-FANCY-PROMPT%>$ _
如果你想不出用 sh
语法重写命令的方法,你总是可以显式调用 bash
或你喜欢的任何其他 shell:
@daily bash -c '...'
这种方式涉及额外的引用层,因此 sh
会将整个命令传递给 bash
而无需尝试解析它。如果这变得太困难,那么将你的命令放在一个脚本中,其中包含一个漂亮的 #!
行和 运行 that 来自 cron.