更改文件名后缀(使用 sed ?)

Posted

技术标签:

【中文标题】更改文件名后缀(使用 sed ?)【英文标题】:Change file name suffix(es) (using sed ?) 【发布时间】:2011-04-11 02:16:21 【问题描述】:

我想更改文件的文件名后缀(使用 bash 脚本),但有时有些文件有一个句点,有些文件有两个。

现在我用这个:

new_file=`echo $file | sed 's/\(.*\.log.*\)'$suf'/\1.'$num'/'`

其中 'new_file' 是新文件名,'file' 是原始文件名,'$suf' 是文件的后缀,$num 是一个新编号。

所以 some.log 必须变成 some.log.1 并且 some.log.1 必须变成 some.log。 2。我的代码 some.log 变成 some.log.1,但 some.log.1 仍然是 some.log.1。

我希望我已经足够清楚了。我感谢任何建议(即使不使用 sed)。

更新:

@paxdiablo。我认为测试出了点问题。

现在我用这段代码作为测试;

#!/usr/bin/bash

        shft() 
            for suff in 6..1 ; do
                if [[ -f "$1.$suff" ]] ; then
                    ((nxt = suff + 1))
                    echo Moving "$1.$suff" to "$1.$nxt"
                    mv -f "$1.$suff" "$1.$nxt"
                fi
            done
            echo Moving "$1" to "$1.1"
            mv -f "$1" "$1.1"
        

        clear

        folder=~/logs/*.log

        for i in 1..20; do
            echo $i> ~/logs/some.log 

            for fspec in $folder ; do
                    shft "$fspec"
            done
        done

现在一切正常。很抱歉造成混乱。

【问题讨论】:

允许建议更好的命名方案避免头痛。比如some.log变成some.log.20100911-013024;下一个some.log 变为some.log.20100911-084137;等等,其中后缀是日志切换的日期/时间。这样可以避免一次重命名多个文件。名称会自动按时间顺序排序。唯一的缺点是您对备份日志的数量没有限制。使用 find . -mtime +183 -name 'some.log.*' -exec rm \; 处理 6 个月以上的日志;调整以适应您的周期时间。 您能否使用您的问题来提供更新,而不是为此目的使用答案。此外,如果您必须说“谢谢”,您可以在评论而不是答案中这样做:blog.***.com/2011/01/how-to-say-thanks-in-an-answer。非常感谢。 【参考方案1】:

如果您希望翻转日志文件,并且取决于您需要获得的复杂程度,我之前使用过以下部分:

#!/usr/bin/bash
# rollover.sh
#   Rolls over log files in the current directory.
#     *.log.8 -> *.log.9
#     *.log.7 -> *.log.8
#     : : :
#     *.log.1 -> *.log.2
#     *.log   -> *.log.1

shft() 
    # Change this '8' to one less than your desired maximum rollover file.
    # Must be in reverse order for renames to work (n..1, not 1..n).
    for suff in 8..1 ; do
        if [[ -f "$1.$suff" ]] ; then
            ((nxt = suff + 1))
            echo Moving "$1.$suff" to "$1.$nxt"
            mv -f "$1.$suff" "$1.$nxt"
        fi
    done
    echo Moving "$1" to "$1.1"
    mv -f "$1" "$1.1"


for fspec in *.log ; do
    shft "$fspec"
    #date >"$fspec" #DEBUG code
done

这将自动将日志文件滚动到版本 9,尽管您可以更改 suff for 循环以允许更多。

添加了DEBUG,以便自动创建新文件进行测试,以下脚本显示了它的实际效果:

pax> touch qq.log ; ./rollover.sh
Moving "qq.log" to "qq.log.1"

pax> touch "has spaces.log" ; ./rollover.sh
Moving "has spaces.log" to "has spaces.log.1"
Moving "qq.log.1" to "qq.log.2"
Moving "qq.log" to "qq.log.1"

pax> ll *log*
-rw-r--r-- 1 pax None 30 2010-09-11 20:39 has spaces.log
-rw-r--r-- 1 pax None  0 2010-09-11 20:39 has spaces.log.1
-rw-r--r-- 1 pax None 30 2010-09-11 20:39 qq.log
-rw-r--r-- 1 pax None 30 2010-09-11 20:38 qq.log.1
-rw-r--r-- 1 pax None  0 2010-09-11 20:38 qq.log.2

这个脚本的好处是它很容易配置以处理大量历史记录(通过更改8..1 位),处理带有空格的名称,并且在日志文件丢失时相对稳健地处理间隙。

【讨论】:

尝试创建我自己的日志轮换脚本,但这个看起来更好。它看起来几乎是需要的 :-)))) 在 some.log.9(数字 10)之后,不是最旧的日志文件被删除,而是第二旧的被删除。最古老的永远存在。我该如何解决这个问题? @Robertico,如果您存储 1 到 9,那么 8 将覆盖 9,因此最旧的将被自动“删除”。如果您已经有 10,只需将 suff 循环更改为您想要的最旧的 - 1。因此,如果您想保持 1 到 50,则循环应该是 49..1 @paxdiablo, 改变 'for suff in 8..1 ;'进入'就在1..9中;'不起作用。在 some.log.1 变为 some.log.10 之后,它将 some.log 重命名为 some.log.1 i> 和 some.log 变成 some.log.1。再次运行脚本。 some.log.10 保留,some.log.1 被删除,some.log 变为 some.log.1我>。有点混乱:-)) @Robertico,您需要以相反的顺序循环,以便按该顺序重命名文件。换句话说,1..9正确,应该是9..1 @paxdiablo。我想我不明白。如前所述,当使用9..1 时,第二旧的日志文件被删除,而不是最旧的。因此,我尝试了1..9,正如您在第二条评论中提到的那样>>*如果您要存储 1 到 9,那么 8 将覆盖 9,因此最旧的将自动被“删除”。* 【参考方案2】:

要轮换日志,你真的应该使用logrotate。

如果你不能依赖 logrotate 可用,这里有一种在 shell 内执行的方法。为简单起见,我假设在您的脚本运行时没有其他任何东西(包括您的脚本的另一个实例)会尝试重命名日志文件。

最简单的方法是在将日志 N 实际重命名为 N+1 之前递归地重命名日志 N+1。 shell 可以执行所有必要的算术运算,这里不需要sed。请注意,虽然在 POSIX shell 中可以使用递归函数,但除了位置参数之外没有局部变量(许多 shell 提供局部变量作为扩展)。

#!/bin/sh
## Move "$1.$2" to "$1.$(($2+1))", first rotating the target as well.
rotate () 
  if [ -e "$1.$(($2+1))" ]; then rotate "$1" $(($2+1)); fi
  mv -- "$1.$2" "$1.$(($2+1))"


for x; do
  ## Break each argument into FILE.NUMBER or just FILE.
  suffix=$x##*.
  case $suffix in
    *[!0-9]*)
      if [ -e "$x.0" ]; then rotate "$x" 0; fi
      mv -- "$x" "$x.0";;
    *) rotate "$x%.*" "$suffix";;
  esac
done

关于你写的内容,注意echo $file 不好有两个原因:最重要的是,如果$file 包含任何特殊字符,例如空格,shell 会解释它们;此外,对于某些 shell,echo 本身将解释反斜杠,并且可能会解释前导 -。所以你应该总是写printf %s "$file"

【讨论】:

正是我所需要的。谢谢。

以上是关于更改文件名后缀(使用 sed ?)的主要内容,如果未能解决你的问题,请参考以下文章

Bash - 使用 sed 更改配置文件

$ sed -i 不更改文件

在 xml 文件中使用 sed 更改值

如何检查 sed 是不是更改了文件

三剑客之sed

find cat sed awk 简单组合使用