Как найти «полную симметричную разницу» нескольких файлов в bash? - PullRequest
1 голос
/ 08 июля 2019

У меня есть пять файлов, в каждом из которых перечислены полные пути к файлам, например, так:

File one
    /full/file/path/one.xlsx
    /full/file/path/two.txt
    /full/file/path/three.pdf
    ....
File two
    /a/b/c/d/r.txt
    /full/file/path/two.txt
    ....
File three
    /obe/two/three/graph.m
    /full/file/path/two.txt
    ....
File four
    .....
File five
     .....

Все пять могут содержать одинаковые точные полные пути к файлам.Тем не менее, я хочу отфильтровать пути, которые являются общими для каждого файла.Другими словами, я хочу, чтобы общее пересечение всех файлов было удалено.Ниже приведено наглядное пособие, описывающее то, что я хочу, с меньшим примером из трех файлов (извините, мои плохие навыки рисования мышью):

enter image description here

Страница на симметричная разница не описывает точно, что я хотел, отсюда наглядное пособие и цитаты вокруг фразы полная симметрическая разница.

Вопрос

Как отфильтровать строки текстав несколько файлов, чтобы получить ситуацию, которую я хочу выше?

1 Ответ

2 голосов
/ 08 июля 2019

Предполагая, что в каждом файле нет дубликатов, вы можете

  • Concat все файлы (cat file1 file2 ... file5)
  • Подсчитайте, как часто появляется каждая строка (sort | uniq -c)
  • И оставляйте только строки, которые появились менее пяти раз (sed -En 's/^ *[1-4] //p')

sort file1 ... file5 | uniq -c | sed -En 's/^ *[1-4] //p'

Однако, если какой-то файл может содержать одну и ту же строку несколько раз, чем вам придется сначала удалить эти дубликаты.

f() { sort -u "$1"; }
sort <(f file1) ... <(f file5) | uniq -c | sed -En 's/^ *[1-4] //p'

или (немного медленнее, но проще для редактирования)

for i in file1 ... file5; do sort -u "$i"; done |
sort | uniq -c | sed -En 's/^ *[1-4] //p'

Если по какой-то причине вы хотите сохранить дубликаты из отдельных файлов, а также хотите сохранить исходный порядок строк, то вы можете инвертировать указанную выше команду только для печати строк, которые появились в каждом файле, и удалить эти строки с помощью grep :

f() { sort -u "$1"; }
grep -Fxvhf <(sort <(f file1) ... <(f file5) |
              uniq -c | sed -En 's/^ *5 //p') file1 ... file5

или (немного медленнее, но проще для редактирования)

files=(file1 ... file5)
grep -Fxvhf <(for i in "${files[@]}"; do sort -u "$i"; done |
              sort | uniq -c | sed -En 's/^ *5 //p') "${files[@]}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...