Bash - 从输入编号开始移动/重命名数字排序文件

Bash - 从输入编号开始移动/重命名数字排序文件

我有一个像这样的文件编号列表:

01_file_name.log
01_file_name.txt
02_file_name.log
02_file_name.txt
03_file_name.log
03_file_name.txt
04_file_name.log
04_file_name.txt
05_file_name.log
05_file_name.txt

我想为所有03*04*文件插入新文件。因此,从病房的编号开始03,所有文件都需要移动/重命名,其前导编号增加 2,因此列表将如下所示:

01_file_name.log
01_file_name.txt
02_file_name.log
02_file_name.txt
05_file_name.log
05_file_name.txt
06_file_name.log
06_file_name.txt
07_file_name.log
07_file_name.txt

我正在考虑这样的事情: bash script.sh 03 02while 03on$1是要开始的文件名的编号和要添加的编号02$2我尝试通过嵌套来实现此目的for-loop,但我不得不放弃使用计数器的组合((++)),以使循环仅运行病房中给定编号的文件。

答案1

这就是你想要的。一件事:我认为它只适用于 BASH。 MAXDIGITS是可选的,我把它放在那里,以防您需要使用三位数或更多。如果不使用,请删除相应行。

    #!/bin/bash

    BOTTOM=$1
    SHIFT=$2
    MAXDIGITS=0$3
    for filename in $(ls -r *.{txt,log}); do
        PREFIX=${filename%%_*}
        NEWPREFIX=$(expr $PREFIX + $SHIFT)
        if [ $PREFIX -ge $BOTTOM ]; then
            NEWPREFIX=$(printf %${MAXDIGITS}d $NEWPREFIX)
            mv $filename ${NEWPREFIX}_${filename#*_}
        fi
    done

使用方法:

    ./myscript <BOTTOM> <SHIFT> <MAXDIGITS>
    ### Example:
    ./miscript 03 02 2 #This means "Start at 03_filename.*, shift the prefixes by 2 and use 2 digits to construct the new prefixes".

如果同一目录中有其他不符合相同语法(prefix_filename.{txt,log})的文件,则必须过滤它们。另外,我使用“_”来分隔前缀和文件名,因此如果您更改它,则需要修复代码。

答案2

就其价值而言,这是一个bash涉及两个的单行流程替代和一个非常简单的awk过程:

$ ls -r -1 *_file_name.{txt,log}    # list initial files in reverse order
05_file_name.log
05_file_name.txt
04_file_name.log
03_file_name.txt
03_file_name.log
03_file_name.txt
02_file_name.log
02_file_name.txt
01_file_name.log
01_file_name.txt

$ source <(awk 'BEGIN{FS="_"} $1>2 {prefix=$1+2; printf ("mv -f %s %0.2d_%s_%s\n",$0,prefix,$2,$3)}' <(ls -r -1 *_file_name.{log,txt}))

$ ls -1 *_file_name.{txt,log}     # list resulting files
01_file_name.log
01_file_name.txt
02_file_name.log
02_file_name.txt
05_file_name.log
05_file_name.txt
06_file_name.log
06_file_name.txt
07_file_name.log
07_file_name.txt

解释:

上面一行是从右到左阅读的,或者至少是“理解”的。

  • ls -r -1 *_file_name.{log,txt} 以一列格式按相反顺序列出要处理的所有文件。
    请注意,如果文件前缀(用 符号表示*)包含非数字字符,您可能会得到不可预见/不需要的结果。为了防止这种情况,请过滤此阶段要处理的文件。

  • <(...)工艺替代。它允许使用文件描述符(即称为命名管道的特殊临时文件)引用先前的结果输出。有关详细信息,请man bash在终端中发布。

  • awk脚本:

    • BEGIN{FS="_"} 在开始处理记录之前,将记录的字段分隔符设置为“_”(awk 的第一个块)
    • awk的第二个块的条件,$1>2:仅处理文件名前缀严格大于2的记录
    • prefix=$1+2定义 awk 的“前缀”内部变量。使其在数值上等于 prefix $1+ 2
    • 用于printf("my_format",var1,var2,...)打印格式化的命令,以换行符分隔。请注意,格式化涉及%0.2d,即将 的变量“前缀”打印awk为两位数,必要时用 0 填充。输出是:
      mv -f 05_file_name.log 07_file_name.log
      mv -f 05_file_name.txt 07_file_name.txt
      mv -f 04_file_name.log 06_file_name.log
      mv -f 04_file_name.txt 06_file_name.txt
      mv -f 03_file_name.log 05_file_name.log
      mv -f 03_file_name.txt 05_file_name.txt
  • 将排序后的输出视为另一个文件(第二个进程替换)并获取它来执行命令mv -f ...

如果您想知道为什么重复使用入站或出站流程替换(不是 POSIX 的东西!) inbash是有利的,请参阅例如。

最后说明:

在上面的一行代码中包含运行时参数并将其封装在可执行 shell 脚本中很容易,从定义VAR1VAR2分配给 的awk过程开始:

$ source <(awk -v VAR1=2 -v VAR2=2 'BEGIN{FS="_"} $1>VAR1 {prefix=$1+VAR2; printf ("mv -f %s %0.2d_%s_%s\n",$0,prefix,$2,$3)}' <(ls -r -1 *_file_name.{log,txt}))

在可执行脚本中script.sh

$ cat script.sh
#!/usr/bin/bash
if [ "$#" -eq 2 ] ; then
    source  <(awk -v VAR1=$1 -v VAR2=$2 'BEGIN{FS="_"} $1>VAR1 {prefix=$1+VAR2; printf ("mv -f %s %0.2d_%s_%s\n",$0,prefix,$2,$3)}' 
              <(ls -r -1 *_file_name.{log,txt})
             )
    exit 0
else
    echo "   Usage: script.sh VAR1 VAR2.\n    Abort execution (exit code 1)."
    exit 1
fi

其中VAR1VAR2具有 OP 中定义的含义。如果您需要在生产环境中使用该脚本,我强烈建议添加许多检查和故障保护,以确保您的输入文件和变量的值始终是预期的。

@MarceloCastro 的脚本很好,尽管它基于for循环,我倾向于尽可能避免这种循环。 for循环往往很慢,如果您处理一个循环,您可能会注意到这一点大的文件数量。

答案3

我制作了这个适合您目标的脚本。

for files in *.extensions
do
  num=$(echo "$files" | awk '{print $1}' | cut -c1-2)
  if [ $num -gt 2 ]; then
     AS=$((num+2))
     temp=$(echo "$files" | cut -c 3-)
     mv $files 0$AS"$temp"
  fi
done

答案4

zsh

$ autoload zmv
$ zmv -n -f '(<3->)(_*)(#qnOn)' '${(l:2::0:)$(($1+2))}$2'
mv -- 05_file_name.txt 07_file_name.txt
mv -- 05_file_name.log 07_file_name.log
mv -- 04_file_name.txt 06_file_name.txt
mv -- 04_file_name.log 06_file_name.log
mv -- 03_file_name.txt 05_file_name.txt
mv -- 03_file_name.log 05_file_name.log

然后删除-n(用于空运行)以实际执行此操作。

  • zmv pattern replacement:zmv是一个可自动加载的函数,它利用强大的 zsh glob 和扩展运算符来执行复杂的文件重命名。
  • <x-y>将十进制数 x 与 y 匹配。
  • (#q...)全局限定符
  • nOn: ame 的n数字order(与大写 O 反转)n。因此,由于我们正在增加数字,因此05...将根据需要在此之前出现。04...
  • ${(l:n::padding:)expansion}l将扩展填充到长度n使用填充。因此${(l:2::0:)},使用 时,将 0 保留到长度 2。
  • $(($1+2)),第一个捕获的组增加 2。
  • $2:第二个捕获组:前导数字之后的内容。

相关内容