【问题标题】:Unix If file exists, renameUnix 如果文件存在,重命名
【发布时间】:2012-04-04 03:54:25
【问题描述】:

我正在处理一个 UNIX 任务,我想检查目录中是否存在特定的日志文件。如果它存在,我想通过在末尾附加时间戳来重命名它。文件名格式如下:ServiceFileName_0.log

这是我目前所拥有的,但是当我运行脚本时它不会重命名,即使存在一个名为 ServiceFileName_0.log 的文件。

renameLogs()
{
   #If a ServiceFileName log exists, rename it

   if [ -f $MY_DIR/logs/ServiceFileName_0.log ]; 
   then
    mv ServiceFileName_0.log ServiceFileName_0.log.%M%H%S
   fi
}

请帮忙!

谢谢

【问题讨论】:

标签: unix timestamp rename


【解决方案1】:

这不是您明显的直接问题,但if 构造是错误的:它引入了time-of-check to time-of-use race conditionif [ -f 检查和mv 之间,可能会出现一些其他进程并更改内容,因此即使检查成功,您也无法再移动文件。

为避免此类错误,请始终编写代码以尝试您想要执行的操作开始,然后如果失败,请找出原因。在这种情况下,如果源文件不存在,您想要什么都不做,但如果由于任何其他原因操作失败,则报告错误。在便携式 shell 中没有好的方法可以做到这一点,您需要一些可以让您检查 errno 的东西。我可能会写这个 C 助手:

#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv)
{
    if (argc != 3) {
        fprintf(stderr, "usage: %s source destination\n", argv[0]);
        return 2;
    }
    if (rename(argv[1], argv[2]) && errno != ENOENT) {
        fprintf(stderr, "rename '%s' to '%s': %s\n", 
                argv[1], argv[2], strerror(errno));
        return 1;
    }
    return 0;
}

然后像这样使用它:

renameLogs()
{
    ( cd "$MY_DIR/logs"
      rename_if_exists ServiceFileName_0.log ServiceFileName_0.log.$(date +%M%H%S)
    )
}

( cd 构造解决了您的直接问题,并且与其他建议不同,它避免了另一个竞争,其中一些其他进程出现并与logs 目录或其父目录混淆。

强制性 shell 脚本附录:始终将变量扩展用双引号引起来,除非在极少数情况下您希望扩展受到分词的影响。

【讨论】:

    【解决方案2】:
    renameLogs()
    {
        if [ -f $MY_DIR/logs/ServiceFileName_0.log ] 
        then mv $MY_DIR/ServiceFileName_0.log $MY_DIR/ServiceFileName_0.log.$(date +%M%H%S)
        fi
    }
    

    一致地使用目录前缀。此外,您还需要正确指定时间,如图所示。

    更好,不过(更少重复):

    renameLogs()
    {
        logfile="$MY_DIR/logs/ServiceFileName_0.log"
        if [ -f "$logfile" ] 
        then mv "$logfile" "$logfile.$(date +%H%M%S)"
        fi
    }
    

    注意:我已将格式从 MMHHSS 重新排序为更传统的 HHMMSS 顺序。如果您也使用日期组件,您应该认真考虑使用 ISO 8601 推荐的顺序,即 [YYYY]mmdd。它将一个月的所有日志文件组合在一个ls 列表中,这通常很有帮助。使用 ddmm 顺序意味着每个月第一天的文件被组合在一起,然后是每个月第二天的文件,依此类推。这通常不太理想。

    【讨论】:

    • 谢谢。如果我想用字符串替换时间,这是正确的语法吗? mv $MY_DIR/ServiceFileName_0.log $MY_DIR/ServiceFileName_0.log.$("Previous") ?
    • 符号$("Previous") 将执行命令Previous 并在重命名过程中使用其输出。不做任何特别的事情,在您的原始文件中,备份将包含文字字符%H%M%S;它们只对少数命令有特殊意义,比如date,这就是我添加date的调用的原因。
    • 非常感谢。非常有帮助。我还有另一个文件,我必须以相同的方式重命名,但文件名为 ServiceFileName_1903.log 。 1903 代表 DDMM,明天将是 2003、2103 等等。我可以在 IF 语句中放入什么通用参数,因为这个数字每次都在变化
    • 使用man date 查找date 的格式参数。您已经从上面的答案中获得了大致的想法,但是详细信息在手册页中进行了描述,并且您应该知道如何在您的机器上使用该版本,或者如何在网络上找到它。
    【解决方案3】:

    你可以替换这个:

    mv ServiceFileName_0.log ServiceFileName_0.log.%M%H%S
    

    有了这个

    mv $MY_DIR/logs/ServiceFileName_0.log $MY_DIR/logs/ServiceFileName_0.log.%M%H%S
    

    【讨论】:

      【解决方案4】:

      您可能需要在文件名前加上 $MY_DIR 路径,就像您在测试中所做的那样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-03-18
        • 1970-01-01
        • 2014-08-09
        • 2014-07-20
        • 1970-01-01
        • 2015-06-14
        • 1970-01-01
        相关资源
        最近更新 更多