批量格式文件名中的数字

[test@localhost rename]$ ll
total 0
-rw-rw-r--. 1 test test 0 Sep 11 09:07 afile-1.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 bfile-10.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 cfile-123.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 dfile-4711.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 efile-20191201.txt

假如存在以上文件,现在需要统一修改文件的名称格式,结果如下

[test@localhost rename]$ ll
total 0
-rw-rw-r--. 1 test test 0 Sep 11 09:07 afile-00000001.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 bfile-00000010.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 cfile-00000123.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 dfile-00004711.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:07 efile-20191201.txt

通过find命令查找文件、再通过awk处理格式。

find . -name "*.txt" | awk -F'[-.]' -v mvCmd='mv -n "%s" "%s"\n' \
    '{ num = $(NF-1);
       files[$0] = num;
       max = num > max? num : max;
     }
     END { width = length(max);
           for(name in files) {
               old = new = name;
               formattedNum = sprintf("%0*d", width, files[name]);
               sub(files[name],formattedNum,new);
               printf mvCmd,old,new;
           }
     }' | sh
  1. 首先通过管道将find的结果传给awk,find后面的逗号代表在当前目录中查找,-name选项执行查找的文件名称匹配格式。
[test@localhost rename]$ find . -name "*.txt"
./afile-1.txt
./bfile-10.txt
./cfile-123.txt
./dfile-4711.txt
./efile-20191201.txt
  1. 通过-F指定分隔符号为-或者.,这样字符串afile-1.txt可以被拆分为afile1txt三个部分,在awk的脚本中就可以通过$(NF)获取最后一个值,也就是txt,而通过$(NF-1)则可以获取倒数第二个值,在这里就是1$0则是文件的完整名称。
[test@localhost rename]$  find . -name "*.txt" | awk -F'[-.]' -v cmd1='key = "%s" ,value = "%s"\n' -v cmd2=' width = "%s"\n' \
>     '{ num = $(NF-1);
>        files[$0] = num;
>        max = num > max? num : max;
>      }
>      END { width = length(max);
>            for(name in files) {
>                printf cmd1,name,files[name];
>            }
>    printf cmd2,width;
>      }'
key = "./cfile-123.txt" ,value = "123"
key = "./dfile-4711.txt" ,value = "4711"
key = "./efile-20191201.txt" ,value = "20191201"
key = "./bfile-10.txt" ,value = "10"
key = "./afile-1.txt" ,value = "1"
 width = "8"

通过哈希表files收集了文件名称以及数字部分的映射关系以及数字部分的最长长度为8.
3. 通过格式化工具生成mv命令。首先将文件名称赋值给old和new变量,然后根据最大长度和当前长度计算格式化的数字并赋值给formattedNum变量。

[test@localhost rename]$  find . -name "*.txt" | awk -F'[-.]' -v cmd1='key = "%s" ,value = "%s",old = "%s",new = "%s",formattedNum = "%s"\n' -v cmd2=' width = "%s"\n' \
>     '{ num = $(NF-1);
>        files[$0] = num;
>        max = num > max? num : max;
>      }
>      END { width = length(max);
>            for(name in files) {
>        old = new = name;
>                formattedNum = sprintf("%0*d", width, files[name]);
>                sub(files[name],formattedNum,new);
>                printf cmd1,name,files[name],old,new,formattedNum;
>            }
>    printf cmd2,width;
>      }'
key = "./cfile-123.txt" ,value = "123",old = "./cfile-123.txt",new = "./cfile-00000123.txt",formattedNum = "00000123"
key = "./dfile-4711.txt" ,value = "4711",old = "./dfile-4711.txt",new = "./dfile-00004711.txt",formattedNum = "00004711"
key = "./efile-20191201.txt" ,value = "20191201",old = "./efile-20191201.txt",new = "./efile-20191201.txt",formattedNum = "20191201"
key = "./bfile-10.txt" ,value = "10",old = "./bfile-10.txt",new = "./bfile-00000010.txt",formattedNum = "00000010"
key = "./afile-1.txt" ,value = "1",old = "./afile-1.txt",new = "./afile-00000001.txt",formattedNum = "00000001"
 width = "8"

最后生成命令对应的字符串

[test@localhost rename]$ find . -name "*.txt" | awk -F'[-.]' -v mvCmd='mv -n "%s" "%s"\n' \
>     '{ num = $(NF-1);
>        files[$0] = num;
>        max = num > max? num : max;
>      }
>      END { width = length(max);
>            for(name in files) {
>                old = new = name;
>                formattedNum = sprintf("%0*d", width, files[name]);
>                sub(files[name],formattedNum,new);
>                printf mvCmd,old,new;
>            }
>      }'
mv -n "./cfile-123.txt" "./cfile-00000123.txt"
mv -n "./dfile-4711.txt" "./dfile-00004711.txt"
mv -n "./efile-20191201.txt" "./efile-20191201.txt"
mv -n "./bfile-10.txt" "./bfile-00000010.txt"
mv -n "./afile-1.txt" "./afile-00000001.txt"
  1. 将生成的命令字符串通过管道符传递给sh就会自动执行这些命令了
[test@localhost rename]$ find . -name "*.txt" | awk -F'[-.]' -v mvCmd='mv -n "%s" "%s"\n' \
>     '{ num = $(NF-1);
>        files[$0] = num;
>        max = num > max? num : max;
>      }
>      END { width = length(max);
>            for(name in files) {
>                old = new = name;
>                formattedNum = sprintf("%0*d", width, files[name]);
>                sub(files[name],formattedNum,new);
>                printf mvCmd,old,new;
>            }
>      }' | sh
mv: ‘./efile-20191201.txt’ and ‘./efile-20191201.txt’ are the same file
[test@localhost rename]$ ll
total 0
-rw-rw-r--. 1 test test 0 Sep 11 09:26 afile-00000001.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:26 bfile-00000010.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:26 cfile-00000123.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:26 dfile-00004711.txt
-rw-rw-r--. 1 test test 0 Sep 11 09:26 efile-20191201.txt

你可能感兴趣的:(shell,linux,服务器,git)