2017-01-21 74 views
0

由于需要使用重命名文件的手动复制和导入工具的组合来完成各种复杂的照片库迁移,看起来我已经清理了大量类似结构的文件。这里有一个例子:如何更改具有相似但不相同结构的所有文件名?

2009-05-05 - 2009-05-05 - IMG_0486 - 2009-05-05 at 10-13-43 - 4209 - 2009-05-05.JPG 

它应该是什么:

2009-05-05 - IMG_0486.jpg 

其他文件具有相同的结构,但显然个别日期和IMG号不同。

有没有什么办法可以在终端中做一些命令行魔术来自动将这些文件重命名为缩短/正确的版本?

+0

文件名应该保留的空间? – Inian

回答

2

我假设你可能有子目录,并希望找到这个目录树中的所有文件。

这第一个代码块(可以放在脚本中)是“安全的”(什么都不做),但会帮助你看看会做什么。

datep="[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" 
dir="PUT_THE_FULL_PATH_OF_YOUR_MAIN_DIRECTORY" 
while IFS= read -r file 
do 
    name="$(basename "$file")" 
    [[ "$name" =~ ^($datep)\ -\ $datep\ -\ ([^[:space:]]+)\ -\ $datep.*[.](.+)$ ]] || continue 
    date="${BASH_REMATCH[1]}" 
    imgname="${BASH_REMATCH[2]}" 
    ext="${BASH_REMATCH[3],,}" 
    dir_of_file="$(dirname "$file")" 
    target="$dir_of_file/$date - $imgname.$ext" 
    echo "$file" 
    echo " would me moved to..." 
    echo " $target" 
done < <(find "$dir" -type f) 

确保输出是你想要的和期待。我无法测试你的实际文件,如果这个脚本没有产生完全令人满意的结果,我不承担任何责任。如果您没有可靠的,经过检查的备份,请不要盲目地让任何人(包括我)通过从互联网上复制和粘贴代码来混淆您的宝贵数据。

一旦确认,决定是否要采取不用于测试任何机会写上一些人的代码有机会和替换echo开始与这三个连续的行:

mv "$file" "$target" 

注意文件名必须匹配到一个非常严格的模式才能进行处理,所以如果您注意到某些文件没有被处理,那么该模式可能需要修改。

1

假设他们都是确切相同的结构,空间和一切,你可以使用awk分割名称使用空格作为中断点。这里有一个快速和肮脏的例子:

#!/bin/bash 
output="" 

for file in /path/to/files/*; do 
    unset output #clear variable from previous loop 
    output="$(echo $file | awk '{print $1}')" #Assign the first field to the output variable 
    output="$output"" - " #Append with [space][dash][space] 
    output="$output""$(echo $file | awk '{print $5}')" #Append with IMG_* field 
    output="$output""." #Append with period 
    #Use -F '.' to split by period, and $NF to grab the last field (to get the extension) 
    output="$output""$(echo $file | awk -F '.' '{print $NF}')" 
done 

从那里,像mv /path/to/files/$file /path/to/files/$output在文件循环将重命名文件最后一行。我会复制一些文件到另一个文件夹中进行测试,因为我们正在处理文件操作。

所有的输出分配行也可以合并到一行中,但它不太容易阅读。

output="$(echo $file | awk '{print $1 " - " $5 "."}')""$(echo $file | awk -F '.' '{print $NF}')" 

不过你仍然需要一个文件循环。

1

假设你要的文件名转换与第一日期和IMG *名称,您可以运行该文件夹在以下方面:

IFS=$'\n' 
for file in * 
do 
printf "mv '$file' '" 
printf '%s' $(cut -d" " -f1,4,5 <<< "$file") 
printf "'.jpg" 
done | sh 
+0

请参阅[为什么你不应该解析ls(1)]的输出(http://mywiki.wooledge.org/ParsingLs),相应地编辑你的答案,以避免得到反对票。这是行不通的 – Inian

+0

我已经加了'IFS = $'\ n''。我在我的本地机器上试过了,它运行了 –

+1

请参阅共享链接,_还注意到ls有时会损坏您的文件名数据(在我们的例子中,它将单词“a”和“newline”之间的换行符转换为问号。有些系统改为\ n)。在某些系统上,当它的输出不是终端时,它不会这样做,而在其他系统上它总是破坏文件名。总而言之,你真的不能也不应该相信ls的输出是你想要使用的文件名的真实表示。所以不要._,我不打算投下它,但它不是最有效的方式,使用'find'! – Inian

相关问题