【问题标题】:Linux Command Line using for loop and formatting results使用 for 循环和格式化结果的 Linux 命令行
【发布时间】:2017-11-06 12:46:49
【问题描述】:

如何使用一个命令行来提供一定大小之间的所有文件的列表,然后使用名称、md5 和文件大小格式化文件。

示例输出应该是

file1.***     MD5 value   size
file2.***     MD5 value   size etc.

我尝试了以下方法,但它在单独的行上显示 md5

find 'directory' -size +30000c -size -50000c | 
while read filename 
   do ls -l "$filename" | awk '{print $9 "\t" $5}' 
   md5sum "$filename" | awk '{print $1}' 
done

它在单独的行上输出带有 MD5 的后续

file1.***   size
MD5

file2.***   size
MD5

【问题讨论】:

    标签: linux loops awk find md5


    【解决方案1】:

    您可以使用rhash 来完成这个简单的任务

    find dir/ -type f -size +30000c -size -50000c -exec rhash -p "%p %m %s\n" {} \;
    
    • -p 以自定义格式打印
    • %p 用于文件路径,%m 用于 md5sum,%s 用于文件大小(以字节为单位)
    【解决方案2】:

    你已经很接近了,只需要一些修复:

    #!/bin/bash
    find ./path/to/dir -type f -size +30000c -size -50000c -printf '%s %p\n' |
    while read -r size filename; do
        md5=$(md5sum "$filename" | awk '{print $1}')
        printf "%-30s %s %10s\n" "$filename" "$md5" "$size"
    done
    

    产生类似的东西:

    ./CHECKSUM                     36e371280a17372537a78167ce22b773        30400
    ./Makefile                     d21464a020be753a9d821cba58f046bc        40000
    

    让我们从find 开始。我们可以通过-printf action 直接从find 获取文件名(路径)和大小%p 指定完整的文件名(相对路径)和%s 文件的大小。我们把%s放在第一位,所以read可以解析它,以防文件名包含空格。另外,我们只对文件感兴趣,所以我们将使用-type f 过滤器。

    接下来,read 可以读取多个字段(以IFS 分隔,默认为空格、换行符和制表符)。如果字段多于给定的变量,则最后一个变量将保存所有剩余字段。此外,我们使用-r 来防止对输入中的转义字符进行(特殊)解释。对于读取的每一行(假设您的文件名不包含换行符),我们会使用您已经使用的命令计算 MD5 和。

    最后,我们使用 shell 内置的printf 来格式化和打印所有字段。格式化 mini 语言类似于 C 的 printf:%-30s 表示左对齐的 30 个字符宽的字符串字段,例如。

    奖励积分:处理带有换行符的文件名。 Unix 文件名可能不能包含的一个字符是 NULL (\0) 字符。虽然bash 不是特别擅长处理二进制(非文本)数据,但我们还是可以做到的:

    #!/bin/bash
    find ./path/to/dir -type f -size +30000c -size -50000c -printf '%s %p\0' |
    while read -r -d '' size filename; do
        md5=$(md5sum "$filename" | awk '{print $1}')
        display_name=$(echo -n "$filename" | tr '\n' '?')
        printf "%-30s %s %10s\n" "$display_name" "$md5" "$size"
    done
    

    首先,我们在-printf 中使用\0 来分隔记录find 输出,并匹配read -d ''。为了使文件名适合在一行中打印,我们必须将所有换行符\n 替换为(但仅用于显示)?。为此,我们可以使用tr,并结合echo -n(请注意,我们不能使用here-string <<<"$filename" 代替echo,因为here-string adds a trailing newline)。

    【讨论】:

      【解决方案3】:

      与其将 find 传递给一组命令,不如直接在 find 中调用这些命令:

      find /p/a/t/h -size +30000c -size -50000c -exec sh -c '
          printf "%s\t" "$1"; md5sum "$1" | cut -d " " -f 1 | tr -d \\n;
          printf "\t";
          stat -c %s "$1"' _ {} \;
      

      请注意,stat 是非标准的,但以上适用于 debian。您可能需要stat -f %z。 YMMV

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-15
        • 1970-01-01
        • 1970-01-01
        • 2020-02-22
        • 2021-07-25
        • 2018-11-06
        • 1970-01-01
        • 2016-10-11
        相关资源
        最近更新 更多