根据属性之一删除重复的JSON文件

时间:2019-03-25 20:52:30

标签: java json shell

我的Linux系统中有两个目录,/dir/dir2

两个都有超过4000个JSON文件。每个文件的JSON内容就像

{
   "someattribute":"someValue",
   "url":[
      "https://www.someUrl.com/xyz"
   ],
   "someattribute":"someValue"
}

请注意,URL是一个数组,但是它始终包含一个元素(URL)。

URL使文件唯一。如果/dir/dir2中的文件具有相同的url,则该文件是重复的,需要将其删除。

我想最好使用shell命令来自动执行此操作。有意见我应该怎么做吗?

4 个答案:

答案 0 :(得分:5)

使用获取重复列表:

jq -nr 'foreach inputs.url[0] as $u (
  {}; .[$u] += 1; if .[$u] > 1
  then input_filename
  else empty end
)' dir/*.json dir2/*.json

要删除它们,请将命令输出上方的管道传输到xargs:

xargs -d $'\n' rm --

或者,为了与具有-0但没有-d的非GNU xargs兼容:

tr '\n' '\0' | xargs -0 rm --

请注意,文件名不得包含换行符。

答案 1 :(得分:1)

这是一个快速且肮脏的bash脚本,它使用jq从json文件中提取URL,并使用awk来检测和删除重复项:

#!/bin/bash

rm -f urls-dir1.txt urls-dir2.txt

for file in dir1/*.json; do
    printf "%s\t%s\n" "$file" $(jq '.url[0]' "$file") >> urls-dir1.txt
done
for file in dir2/*.json; do
    printf "%s\t%s\n" "$file" $(jq '.url[0]' "$file") >> urls-dir2.txt
done

awk -F $'\t' 'FNR == NR  { urls[$2] = 1; next }
              $2 in urls { system("rm -f \"" $1 "\"") }' urls-dir1.txt urls-dir2.txt

rm -f urls-dir1.txt urls-dir2.txt

假定dir2中有要删除的文件作为重复文件,而dir1中的文件应保持不变。

答案 2 :(得分:1)

您可以使用以下Java方法来实现此目的:

Set<String> urls = new HashSet<>();
try (Stream<Path> paths = Files.list(Paths.get("/path/to/your/folder"))) {
    paths
            .map(path -> new FileInfo(path, extractUrl(path)))
            .filter(info -> info.getUrl() != null)
            .filter(info -> !urls.add(info.getUrl()))
            .forEach(info -> {
                try {
                    Files.delete(info.getPath());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
} catch (IOException e) {
    e.printStackTrace();
}

这使用以下FileInfo类:

public class FileInfo {
    private Path path;
    private String url;
    // constructor and getter
}

首先,它读取给定目录中的所有文件并提取URL。它借助HashSet过滤所有重复项。最后,所有包含重复URL的文件都将被删除。

有多个选项可从每个文件中提取url

使用正则表达式又快又脏:

private String extractUrl(Path path) {
    try {
        String content = String.join("\n", Files.readAllLines(path));
        Pattern pattern = Pattern.compile("\"url\".+\\s+\"(?<url>[^\\s\"]+)\"");
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            return matcher.group("url");
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

更好的解决方案是使用Jackson之类的JsonParser库:

private String extractUrl(Path path) {
    try (BufferedReader reader = Files.newBufferedReader(path)) {
        ObjectMapper mapper = new ObjectMapper();
        MyObject object = mapper.readValue(reader, MyObject.class);
        return object.getUrls().stream().findFirst().orElse(null);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

这使用文件内容的对象表示形式:

public class MyObject {
    @JsonProperty("url")
    private List<String> urls;
    // getter and setter
}

但是最后,性能最高的解决方案可能是使用shell脚本。

答案 3 :(得分:0)

这是一个快速简单的awk脚本,它可以从基本目录执行所有工作。

名为script1.awk的awk脚本

/https/{
    if ($1 in urlArr) {
        cmd = "rm " FILENAME;
        print cmd;
        //system(cmd);
    } else {
        urlArr[$1] = FILENAME;
    }
}

首先使用以下命令运行脚本:

awk -f script1.awk dir{1,}/*.json

准备删除重复的json文件时,只需取消注释第5行(包含system(cmd)的行)。并再次运行。

以下是一些解释:

  1. awk命令在子目录dir和dir1中的所有json文件上运行脚本script1.awk

  2. 脚本遍历每个文件,将具有https的URL文本提取到变量$ 1中。

    如果关联数组urlArr中已经存在变量$ 1,则打印/删除文件。

    否则将当前文件添加到关联数组urlArr中。

希望您喜欢这个简单的解决方案。