
Допустим, у меня есть две команды, которые возвращают какой-то текст. Например:
$ ./c1
/usr/bin/foo
/usr/bin/bar
/usr/bin/baz
$ ./c2
/usr/bin/foo
/usr/bin/qux
/usr/bin/buzz
/usr/bin/bar
Я хочу удалить дубликаты строк; т.е. вывод будет таким (порядок не важен):
/usr/bin/baz
/usr/bin/qux
/usr/bin/buzz
Как бы я это сделал?
решение1
Достаточно простой конвейер должен справиться с этой задачей:
(./c1; ./c2) | sort -u
Скобки получают stdout обоих ./c1
и ./c2
stdin команды sort
. Опция -u
печатает только 1 из каждой группы совпадающих строк.
Спасибо Джону У. Х. Смиту за то, что он заметил упрощение, и Бакуриу за понимание.
решение2
С comm
из GNU coreutils
:
$ comm -3 <(sort -u <(./c1)) <(sort -u <(./c2)) | tr -d '\t'
/usr/bin/baz
/usr/bin/buzz
/usr/bin/qux
От man comm
:
Compare sorted files FILE1 and FILE2 line by line.
With no options, produce three-column output. Column one contains
lines unique to FILE1, column two contains lines unique to FILE2, and
column three contains lines common to both files.
-1 suppress column 1 (lines unique to FILE1)
-2 suppress column 2 (lines unique to FILE2)
-3 suppress column 3 (lines that appear in both files)
решение3
awk-pipe, чтобы пропустить только первое вхождение входной строки:
( ./c1 ; ./c2 ) | awk '!u[$0]++'
Это не требует времени на сортировку, но требует памяти увиденных строк. Так что для больших объемов ввода sort
и uniq
может быть лучше...
решение4
Я бы рекомендовал использовать sed
для разбора текста и удаления дубликатов строк. Так что первая команда сохраняет дубликаты строк
sed '$!N; /^\(.*\)\n\1$/!P; D'
Вторая команда удалит дубликаты.
sed -n 'G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P'