0

我正在尝试在我的 crontab 文件中附加一行。我知道还有其他方法可以解决这个问题,但仍然想知道是什么原因造成的。该命令在树莓派 3 B+ 上运行,安装了 raspbian lite,GNU ed 1.15,cron 3.0pl1-134+deb10u1。

我坚持的命令是:

$ echo -e 'a\n#asdf\n.\nwQ' | EDITOR=ed crontab -e
902
909
No modification made

我希望它#asdf在我的 crontab 文件末尾添加行,但事实并非如此。

按照https://stackoverflow.com/a/30123606/8842387EDITOR='tee -a'上的建议进行设置并不能解决问题。所以我想这是cron的问题。

奇怪的是,当我直接从键盘发出 ed 命令而不是流式传输它时,它就可以工作了。也许子shell创建导致了问题?

在这里,我附上了strace结果中的最后几行。

$ echo -e 'a\n#asdf\n.\nwQ' | EDITOR=ed strace crontab -e
execve("/usr/bin/crontab", ["crontab", "-e"], 0x7ee54c14 /* 29 vars */) = 0
access("/etc/suid-debug", F_OK)         = -1 ENOENT (No such file or directory)
...
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\7\0\0\0\7\0\0\0\0"..., 4096) = 659
_llseek(3, -393, [266], SEEK_CUR)       = 0
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\7\0\0\0\7\0\0\0\0"..., 4096) = 393
close(3)                                = 0
getpid()                                = 18579
socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/dev/log"}, 110) = 0
send(3, "<78>Nov 20 15:31:25 crontab[1857"..., 56, MSG_NOSIGNAL) = 56
openat(AT_FDCWD, "crontabs/pi", O_RDONLY) = -1 EACCES (Permission denied)
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
fstat64(4, {st_mode=S_IFREG|0644, st_size=2995, ...}) = 0
read(4, "# Locale name alias data base.\n#"..., 4096) = 2995
read(4, "", 4096)                       = 0
close(4)                                = 0
openat(AT_FDCWD, "/usr/share/locale/en_GB.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_GB.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en_GB/LC_MESSAGES/libc.mo", O_RDONLY) = 4
fstat64(4, {st_mode=S_IFREG|0644, st_size=1433, ...}) = 0
mmap2(NULL, 1433, PROT_READ, MAP_PRIVATE, 4, 0) = 0x76f50000
close(4)                                = 0
openat(AT_FDCWD, "/usr/share/locale/en.UTF-8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en.utf8/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, "crontabs/pi/: fdopen: Permission"..., 39crontabs/pi/: fdopen: Permission denied) = 39
exit_group(1)                           = ?
+++ exited with 1 +++

openat(AT_FDCWD, "crontabs/pi", O_RDONLY) = -1 EACCES (Permission denied)看起来有点可疑,但不确定为什么它以只读方式打开文件。

编辑:正如@tink 所建议的,我跑去EDITOR=ed strace crontab -e看看strace在交互式会话中给出了什么。结果几乎相同(仅在 pid 和 fd 编号上有所不同)。

我注意到运行echo "..." | EDITOR=ed crontab -e退出并显示消息No modification made,但strace进程停止但没有任何消息。(EDITOR=ed strace crontab -e 2>&1 | grep "No mod"什么都不打印)。猜猜 strace 会触发不同的错误。

4

2 回答 2

0

跟进我的视觉评论,这些对我有用:

( unset VISUAL; printf '%s\n' a '#abcd' . wq | EDITOR=ed crontab -e )
printf '%s\n' a '#abcd' . wq | VISUAL=ed crontab -e

在我的环境中,VISUAL 和 EDITOR 都设置为“vim”

或者,更迂回,但不需要与 env vars 一起玩。这也允许你默默地做到这一点:

crontab <(printf '%s\n' a '#asdf' . '%p' | ed -s <(crontab -l))

我在 Mac 上执行上述操作。在 Linux 上,我可以重现您的观察结果,但无法解释它们。

对最后一个命令进行小调整:

printf '%s\n' a '#asdf' . '%p' Q | ed -s <(crontab -l) | crontab -
于 2021-11-20T15:29:47.623 回答
0

TLDR ; (sleep 1; echo -e 'a\n#asdf\n.\nwQ') | EDITOR=ed crontab -e作品!

问题出在crontab.

当我调用它时,它会在目录crontab -e中创建用户 cron 表的临时副本。/tmp然后使用指定的编辑器打开临时文件$EDITOR。编辑完成后,crontab检查文件修改日期自创建以来是否已更改。这是在允许通过临时文件编辑 cron 表的补丁中实现的。

就我而言,ed从完成编辑中获取命令stdin的速度太快,以至于临时文件的修改时间戳的一位数都没有被更改。由于crontab认为没有人可以如此快速地进行编辑,因此它假定没有进行任何修改并丢弃它。

为了绕过这种行为,我sleep 1在发布之前添加了该命令。这将在创建临时文件后ed等待它的命令,这有效地让修改时间戳不同。stdincrontab

于 2021-12-28T11:16:23.590 回答