2010-09-08 130 views
45

我有一个包含约1,700个文件的文件夹。他们都被命名为1.txt1497.txt等。我想重命名所有文件,以便所有文件名都是四位数字。Linux shell脚本将前导零添加到文件名

即,23.txt变成0023.txt

什么是将执行此操作的shell脚本?或者一个相关的问题:我如何使用grep来匹配只包含\d.txt的行(即一个数字,然后是句点,然后是字母txt)?

这是我到目前为止有:

for a in [command i need help with] 
do 
    mv $a 000$a 
done 

基本上,运行三次,命令那里找一个数字,两个数字,三位数字的文件名(与初始零的数量改变)。

+1

你应该用你使用[bash脚本的 – meagar 2010-09-08 22:17:07

+0

可能的复制壳标签这个来填充文件名](http://stackoverflow.com/questions/55754/bash-script-to-pad-file-names) – 2015-10-01 07:41:38

+1

@CiroSantilli,顺便说一句,我最近有人推迟了一个被关闭的重复作为填充前导数字的逻辑以及稍后在名称中填充填充数字的逻辑有所不同。 (因此,https://stackoverflow.com/questions/46993470/padding-filenames-with-zeros-in-bash目前标记了这个答案的愚蠢,*而不是*那个愚蠢的)。 – 2017-10-28 20:04:48

回答

46

尝试:

for a in [0-9]*.txt; do 
    mv $a `printf %04d.%s ${a%.*} ${a##*.}` 
done 

根据需要更改文件名模式([0-9]*.txt)。


通用枚举重命名不作任何初始设置文件名的假设:

X=1; 
for i in *.txt; do 
    mv $i $(printf %04d.%s ${X%.*} ${i##*.}) 
    let X="$X+1" 
done 

关于同一主题:

+0

这会为每个已经有4位数的文件名输出一串错误。在开始时加入foo会解决这个问题,但我不想那样做。感谢这些链接。 – 2010-09-08 22:30:03

+0

对不起,“foo”...错误的复制/粘贴 – 2010-09-08 22:32:34

0

要只匹配单个数字的文本文件,你可以做...

$ ls | grep '[0-9]\.txt' 
+0

有没有办法从$ a中删除'.txt'?我以前曾经好几次想过。 – 2010-09-08 22:22:06

+0

是的,'$ {a%.txt}'会这样做(或者'$ {a%。*}'来删除任何后缀)。 – 2010-09-08 22:24:14

+0

如果你知道扩展之前的快速方法是通过sed来管道输出,就像这样:'ls | grep'[0-9] \。txt'| sed's/\ txt // g'' – LukeN 2010-09-08 22:24:34

11
for a in *.txt; do 
    b=$(printf %04d.txt ${a%.txt}) 
    if [ $a != $b ]; then 
    mv $a $b 
    fi 
done 
+0

感谢您的答案!基本上与另一个完全相同的时间相同。 – 2010-09-08 22:32:41

+1

@David:我的解决方案不会导致一堆错误。 :-P – 2010-09-08 22:33:29

+0

如果**输入文件名没有空格,则不会导致错误**。应该添加更多的引号来避免这种情况。 :) – 2017-10-28 19:52:44

7

一衬垫:

ls | awk '/^([0-9]+)\.txt$/ { printf("%s %04d.txt\n", $0, $1) }' | xargs -n2 mv 

如何用grep包含\ d.txt仅匹配线(IE 1位,则一个周期,那么字母txt)?

grep -E '^[0-9]\.txt$' 
12

使用有时用Perl安装renameprename在某些情况下)脚本,您可以使用Perl表达式来完成重命名。脚本跳过重命名,如果有名称冲突。

下面的命令仅重命名具有四位或更少位数的文件,后跟“.txt”扩展名。它不会重命名不严格符合该模式的文件。它不会截断包含多于四位数字的名称。

rename 'unless (/0+[0-9]{4}.txt/) {s/^([0-9]{1,3}\.txt)$/000$1/g;s/0*([0-9]{4}\..*)/$1/}' * 

举几个例子:

Original Becomes 
1.txt  0001.txt 
02.txt  0002.txt 
123.txt  0123.txt 
00000.txt 00000.txt 
1.23.txt 1.23.txt 

其它给出的答案迄今将尝试对包含非数字字符的文件名命名不符合模式的文件,产生误差,进行重命名这会产生名称冲突,请尝试重新命名文件名称中有空格的文件,以及可能存在的其他问题。

+0

Yagni。认真。谁关心包含空格或非数字字符的文件名,如果这不在问题的范围之内?如果OP想写一个通用脚本,他在问题中会这样说,并且答案会相应地适应。 – 2010-09-15 19:41:16

+13

@Chris:我的答案经常做两件事。一,他们试图回答OP的问题。二,他们试图提供可能对未来的观众有用的附加信息。 – 2010-09-16 00:17:36

+2

@ Dennis:谢谢你提供这个,最高评分的答案并没有解决我的特殊问题,但正如你所指出的那样,你提供了一个更广泛和更广泛的答案,这有助于。谢谢。 – 2013-04-26 08:48:22

4

假设您的文件夹中包含数据类型为.dat的文件。就在这个代码复制到一个文件名为run.sh,运行chmode +x run.sh使其可执行文件,然后执行使用./run.sh

#!/bin/bash 
num=0 
for i in *.dat 
do 

    a=`printf "%05d" $num` 
    mv "$i" "filename_$a.dat" 
    let "num = $(($num + 1))" 
done 

这将所有文件转换您的文件夹中filename_00000.datfilename_00001.dat

0

单行提示:

while [ -f ./result/result`printf "%03d" $a`.txt ]; do a=$((a+1));done 
RESULT=result/result`printf "%03d" $a`.txt 
1

此版本还支持在数字之前(之后)处理字符串。但基本上你可以做任何正则表达式匹配+ printf,只要你的awk支持它。它也支持文件名中的空白字符(除了换行符)。

for f in *.txt ;do 
    mv "$f" "$( 
     awk -v f="$f" '{ 
      if (match(f, /^([a-zA-Z_-]*)([0-9]+)(\..+)/, a)) { 
       printf("%s%04d%s", a[1], a[2], a[3]) 
      } else { 
       print(f) 
      } 
     }' <<<'' 
    )" 
done 
+0

我刚刚尝试了上面的内容,它吹走了目录中的所有文件并留下了一个文件“0000”。 – Ryan 2017-08-28 20:49:47

+0

@Ryan这意味着正则表达式不匹配你的目录中的任何文件。你必须自定义正则表达式+ printf来完成任何事情。上面的代码只是一个例子。 – rindeal 2017-08-31 20:50:15

+0

rindeal是正确的。当我纠正我的文件名正则表达式(我有空格)它的工作。与正则表达式不匹配的文件名仍然会移至'0000',这可能有点令人惊讶。如果您正在进行批量重命名并尝试使用随机脚本,那么您最好有备份。 – Ryan 2017-09-01 20:24:29

0

为了提供真实谨慎写是正确的,即使在文件名的存在与空间的解决方案:

#!/usr/bin/env bash 

pattern='%04d' # pad with four digits: change this to taste 

# enable extglob syntax: +([[:digit:]]) means "one or more digits" 
# enable the nullglob flag: If no matches exist, a glob returns nothing (not itself). 
shopt -s extglob nullglob 

for f in [[:digit:]]*; do    # iterate over filenames that start with digits 
    suffix=${f##+([[:digit:]])}   # find the suffix (everything after the last digit) 
    number=${f%"$suffix"}     # find the number (everything before the suffix) 
    printf -v new "$pattern" "$number" "$suffix" # pad the number, then append the suffix 
    if [[ $f != "$new" ]]; then     # if the result differs from the old name 
    mv -- "$f" "$new"       # ...then rename the file. 
    fi 
done