将目录中的所有文件重命名为其文件名的 md5 哈希值(不是内容)

将目录中的所有文件重命名为其文件名的 md5 哈希值(不是内容)

我对 linux / 命令行非常陌生,需要加密 10K+ 文件的名称(唯一名称),以便它们与 mySQL 数据库中的 MD5 加密名称匹配。
我已经了解了如何重命名文件目录以及如何获取文件的哈希值(mdsum?)但我坚持如何获取文件名的哈希,然后将该文件重命名为生成的哈希,保留扩展名 ie

mynicepicture.jpg > fba8255e8e9ce687522455f3e1561e53.jpg 

看起来它应该是一个简单的重命名或mv行,但我无法理解它。
非常感谢您的见解

PS 我已经在一些接近我正在寻找的示例中看到了 Perl 函数的使用,但不知道在哪里/如何使用它们。

答案1

你没有说你想使用哪个外壳,所以我只是假设重击– 答案需要调整才能与其他 shell 一起使用。

for i in *; do sum=$(echo -n "$i"|md5sum); echo -- "$i" "${sum%% *}.${i##*.}"; done

脚本版本:

for i in *; do
  sum=$(echo -n "$i" | md5sum)
  echo -- "$i" "${sum%% *}.${i##*.}"
done

这个简单的for循环获取当前目录中的每个文件,计算其名称的 md5 和并将其输出。使用它来检查功能,如果您想开始重命名,请将第二个替换echomv.

说明

  • echo -n "$i" | md5sum– 计算 md5 和完整文件名包括文件扩展名(管道),将扩展名更改echo -n "$i"为以下之一:

    ${i%%.*}
    sed 's/\..*//' <<< "$i"
    echo "$i" | sed 's/\..*//'
    
  • sum=$(…)– 执行并将输出保存在$sum(命令替换

  • ${sum%% *}– 输出所有内容,直到第一个空格(参数替换),与以下之一相同:

    $(sed 's/ .*//' <<< "$sum")
    $(echo "$sum" | sed 's/ .*//')
    
  • ${i##*.}– 输出最后一个点之后的所有内容(参数替换),与以下之一相同:

    $(sed 's/.*\.//' <<< "$i")
    $(echo "$i" | sed 's/.*\.//')
    

如果需要在不同文件夹中递归地重命名文件,请使用find-exec选项。

答案2

#!/bin/bash

md5name () {
    local base=${1##*/}
    local ext=${base##*.}
    local dir=${1%/*}

    printf '%s' "${base%.$ext}" | md5sum |
    awk -v dir="$dir" -v ext="$ext" '{ printf("%s/%s.%s\n", dir, $1, ext) }'
}

dir=$HOME  # where your files are

for pathname in "$dir"/*; do
    test -f "$pathname" || continue
    echo mv "$pathname" "$( md5name "$pathname" )"
done

bash脚本使用md5sumGNU coreutils 中的实用程序根据任何给定路径名的基本名称(无扩展名)计算 MD5 哈希值。辅助函数md5name执行实际计算,并将输出带有完整路径和扩展名的新名称。

md5name函数用于awk根据给定路径名的部分和 的结果组装新名称md5sum

函数本身使用的示例:

$ md5name '/some/path/file name here.extension'
/some/path/c9e89fa443d16da4b96ea858881320c9.extension

...c9e89fa443d16da4b96ea858881320c9字符串的 MD5 哈希值在哪里file name here

echo从顶部的脚本中删除 来实际重命名文件。echo如果您在某些时候需要将文件名恢复为其原始名称,您可能希望将原始脚本的输出保存到文件(就地)。

请注意,运行此两次在一组文件上将计算 MD5 哈希值的 MD5 哈希值,并且原始文件名将变得不可恢复,除非您仔细记录每次运行脚本后哪些文件的名称。

答案3

perlrename

find . -name '*.jpg' -type f -exec rename -n '
  BEGIN{use Digest::MD5 qw(md5_hex)}
  my ($dir, $name, $ext) = m{(.*)/(.*)\.(.*)}s;
  $_ = "$dir/" . md5_hex($name) . ".$ext"' {} +

(高兴时删除 -n)。

答案4

对于一种AWK方法:

find [Directory] -type f [various other find options] | 
     awk '{orig=$0; 
           match($0,/^.*\//,path); sub("^"path[0], "");
           match($0, /.[[^.]+$/,ext); sub(ext[0]"$", "");
           ("echo \"" $0 "\"|md5sum") | getline;
           com=sprintf("mv \"%s\" \"%s%s%s\"", orig, p[0], $1, ext[0]);
           print(com)
           }'

假定现代find命令不需要输入目录.,因此 [Directory] ​​可以留空。唯一-type f的查找文件,这很方便,因为md5sum不喜欢目录并且在运行时更改目录名称不是一个好主意。-iname pattern如果您只想使用某些文件,请使用,例如-iname \*.dat,如果大小写很重要,请使用-name而不是-iname

这些match(...); sub(...)片段提取文件名的部分并在输入字符串中替换它们。请注意, [pre/app] 附加"^""$"是为了防止替换可能重复路径/扩展名的字符串。

替换print(com)system(com)实际执行重命名,例如:

find -type f | 
     awk '{orig=$0; 
           match($0,/^.*\//,path); sub("^"path[0], "");
           match($0, /.[[^.]+$/,ext); sub(ext[0]"$", "");
           ("echo \"" $0 "\"|md5sum") | getline;
           com=sprintf("mv \"%s\" \"%s%s%s\"", orig, p[0], $1, ext[0]);
           system(com)
           }'

如果您想使用md5sum实际文件的名称作为名称md5sum您可以利用输出总和和输入文件名的事实来执行以下操作:

 find -type f -exec md5sum '{}' ';' | 
     while read sum file ; do 
       [echo] mv "$file" "`dirname $file`/$sum".extension ; 
     done

while read sum file采用 2 个参数,即命令的结果md5sum,并使用它们进行赋值sum和变量。file由于sum其中不应有空格,因此read应该可以正常工作。

显然,[echo]在实际运行时应该将其删除,但在运行之前测试任何脚本更改以测试搜索时,这始终是一个好主意。

这一切都假设你正在跑步bash。另外,这可以输入为较长的一行:

find -iname \*.jpg -exec md5sum '{}' ';' | while read sum file ; do mv "$file" "`dirname $file`/$sum".jpg ; done

相关内容