首页 > 解决方案 > Bash 创建 JSON 文件清单

问题描述

我有一个 bash 脚本来输出带有 MD5 哈希的文件清单作为 JSON,如下所示:

{
 "files": [
    {
      "md5": "f30ae4b2e0d2551b5962995426be0c3a",
      "path": "assets/asset_1.png"
    },
    {
      "md5": "ca8492fdc3547af31afeeb8656619ef0",
      "path": "assets/asset_2.png"
    },
  ]
}

它将返回除 .gdz 之外的所有文件的列表。

我正在使用的命令是:

echo "{\"files\": [$(find . -type f -print | grep -v \.gdz$ | xargs md5sum | sed 's/\.\///' | xargs printf "{\"md5\": \"%s\", \"name\": \"%s\"}," | sed 's/,$//')]}" > files.json

但是,当我在生产中运行它时,它有时会切换 MD5 哈希和文件路径。我不知道这是为什么,有人知道吗?

标签: jsonbashmd5manifest

解决方案


在 shell 中稳健地执行此操作有点痛苦。您必须担心文件名中的空格(这会破坏您当前的代码)、正确编码和转义您的 JSON 字符串(如果您的文件名称中包含引号怎么办?)等。

一个执行相同操作的快速perl脚本,将要扫描的目录作为命令行参数传递:

#!/usr/bin/env perl
use warnings;
use strict;
use File::Find;
use Digest::MD5;
use JSON::PP; # Or JSON::XS if installed

my @hashes;

find(\&wanted, @ARGV);
print JSON::PP->new->ascii->encode({files => \@hashes});

sub wanted {
    if (-f $_ && $_ !~ /\.gdz$/) {
        my $name = $File::Find::name;
        $name =~ s!^\./!!;
        open my $f, "<:raw", $_ or
            die "Couldn't open $name: $!\n";
        push @hashes, { path => $name,
                        md5 => Digest::MD5->new()->addfile($f)->hexdigest
        };
        close $f;
    }
}

推荐阅读