如何使用bash脚本批量重命名文件?

如何使用bash脚本批量重命名文件?

我在一个目录中有多个文件,格式如下,所以我想重命名所有文件,如下所示:

27_07_2017file1vc001vpxd-1605.log
27_07_2017case2vc001vpxd-9169.log
27_07_2017server3vc001vpxd-4640.log
27_07_2017file24vc001vpxd-9170.log
27_07_2017files5vc001vpxd-4641.log

file1vc001vpxd-1605_27_07_2017_1.log
case2vc001vpxd-9169_27_07_2017_1.log
server3vc001vpxd-4640_27_07_2017_1.log
file24vc001vpxd-9170_27_07_2017_1.log
files5vc001vp-4641_27_07_2017_1.log

需要将文件格式从 更改datefilename.log为 格式filename.date_1.log

请不要建议使用rename命令,因为它在我的 Linux 服务器上不起作用。

谢谢

答案1

这是一个 bash 脚本(针对一般情况进行修订基于OP修改后的问题):

for file in ./*.log; do 
    echo mv "$file" "${file:12:$((${#file}-16))}_${file:2:10}_1.log";
done

上面${file:X:Y}是bash子串扩展语法${variable:offset:length}并得到长度字符数从抵消从它的variable(或参数)并用mv命令重命名。echo一旦您确保结果如您所愿,只需删除即可。

上面的结果如下:

mv ./27_07_2017case5.log case5_27_07_2017_1.log
mv ./27_07_2017file1vc001vpxd-1605.log file1vc001vpxd-1605_27_07_2017_1.log
mv ./27_07_2017file2vc001vpxd-9169.log file2vc001vpxd-9169_27_07_2017_1.log
mv ./27_07_2017file3vc001vpxd-4640.log file3vc001vpxd-4640_27_07_2017_1.log
mv ./27_07_2017file4vc001vpxd-9170.log file4vc001vpxd-9170_27_07_2017_1.log
mv ./27_07_2017file5.log file5_27_07_2017_1.log
mv ./27_07_2017file5vc001vpxd-4641.log file5vc001vpxd-4641_27_07_2017_1.log
mv ./27_07_2017number-blahblahblah5.log number-blahblahblah5_27_07_2017_1.log
mv ./27_07_2017number-blahblahblah5AAABBC.log number-blahblahblah5AAABBC_27_07_2017_1.log
mv ./27_07_2017number5.log number5_27_07_2017_1.log

答案2

在你的情况下有两个组成部分: 文件名日期

使用递归搜索列出所有日志文件

find "$(pwd)" -type f -iname "*.log" > loglist

列出所有日志文件而不递归到子目录

find "$(pwd)" -maxdepth 0 -type f -iname "*.log" > loglist

现在,使用while循环您可以将文件移动到所需的格式

while read f;
do
    # filename only and not complete path
    fname_only=$(basename "$f");
    
    # directory name only without filename
    dirname_only=$(dirname "$f");
    
    # use cut command to extract first 10 characters as date from filename
    date_only=$(echo "$fname_only" | cut -c 1-10);

    # use cut command to extract 11th character onward as new filename with extension
    fname_extract=$(echo "$fname_only" | cut -c 11-);

    # filename with complete path without extension 
    fname_no_extns="${fname_extract%.*}"

    # Now, move files to their desired format recursively
    mv "$f" "${dirname_only}/${fname_no_extns}.${date_only}_1.log"

done < loglist

答案3

我不知道文件名的所有可能情况,因此我将向您展示一种可以适应您的需求的通用方法。

您可以使用循环遍历文件forfind -exec根据需要使用。我认为您主要想知道如何将文件名切成碎片并以不同的方式将它们组合在一起。

您可以将名称通过管道传输到类似的工具中sed,并创建正则表达式来标识您需要的部分:

newname=`echo "$oldname"|sed -E 's/([0-9-]{10})(.*).log/\2_\1_1.log/'`

如果您将()这些部分放在周围,则可以在替换字符串中将它们引用为\1\2等等。如果您需要调整它,请阅读页面,man或者sed如果您没有成功,请在此处询问。

另一种可能性是使用 POSIX 变量扩展:

你可能知道

${oldname#*201?}

将删除文件名的日期前缀(可以?匹配任何字符,因此这适用于 2010 年至 2019 年,如果足够的话。否则请适应。)

您还可以将它们组合起来:

${oldname%${oldname#*201?}}

将删除我们上面提取的部分,因此这只会为您提供日期。通过这种方式,您可以分隔文件名的各个部分并以不同的顺序粘贴它们。

答案4

强制性的 zsh + zmv 答案:

autoload -Uz zmv
zmv -n '(<1-31>_<1-12>-<1900-2999>)(*).log' '$2.${1}_1.log'

如果满意,请删除-n(用于试运行)。

相关内容