有一个定期下载东西的 cronjob:
if ! su scpuser -c "scp ..." > /dev/null 2>&1 || ! [ -f $scptarget ]; then;
error "did not download stuff"
$scptarget
是下载内容的位置,并且它与正在运行的脚本位于不同的卷上(但不是不同的状态,我认为是相同的硬盘驱动器)
每次出错时,我们都会进去查看,文件就在那里。如果稍微放松一下,检查文件是否存在的部分是否有可能成功?或者,即使 SCP 成功了,它也会抛出错误吗?
(我希望最初写这篇文章的人能记录下实际的错误是什么,我只是抓住了救命稻草)
如果是这样,我不想sleep
在这个脚本中添加任意内容,是否有真正的 bash 程序员所做的更经典的事情?
答案1
我strace
对scp
一个文件做了一个。在我看来,它不像scp
那样使用临时文件名wget
,它实际上检查目标文件是否存在,并使用O_WRONLY|O_CREAT
.如果scp
实际有数据要写出,则目标文件应该存在。
目标文件存在和检查其存在之间不可能发生“竞争”。 shell 必须在scp
退出时获得 SIGCHLD 才能获取退出状态并确定状态为非零。我很确定内核会在进程退出时处理现有的文件名scp
。文件创建应该是原子的。不要费心添加一个sleep
,它没有帮助。
示例代码到达目标文件存在性测试 ( [ -f $scptarget ]
) 的唯一方法是以scp
0(零)状态退出。该文件当然可能存在,但存在错误情况。$scptarget
当发生错误时,您是否检查文件的正确性和完整性?您可能会得到不完整的或损坏的文件。
我认为要弄清楚发生了什么,您必须使用 2 个if
构造,第一个用于 的退出状态scp
,第二个用于目标文件的存在。确保消息不同,并且您记录了进程$?
的退出状态scp
。
答案2
首先获取错误代码(stderr 也可能很有用。谁制作的脚本不记录错误...?)。 'su' 或 'scp' 可能返回 retVal>0。
OSX 的 SCP 源代码片段:
// I'd put my bet for this case..
void
lostconn(signo)
int signo;
{
if (!iamremote)
fprintf(stderr, "lost connection\n");
exit(1);
}
确保失败后目标文件与源文件完全相同...
摘自苏联机帮助页:
退出价值
成功后,su 返回其执行的命令的退出值。
如果该命令由信号终止,则 su 返回该信号的编号加 128。
如果 su 必须终止该命令(因为它被要求终止,而该命令没有及时终止),su 将返回 255。
再次..如果没有退出代码或 stderr 内容,除了继续猜测之外我们无能为力。