Ответ 1
Основное решение, использующее sed
, полагается на то, что comm
выводит строки, найденные только в первом файле без префикса; он выводит строки, найденные только во втором файле, с одной вкладкой; и он выводит строки, найденные в обоих файлах, с двумя вкладками.
Он также полагается на sed
w
команду для записи в файлы.
Данный файл 1.sorted.txt
содержащий:
1.line-1
1.line-2
1.line-4
1.line-6
2.line-2
3.line-5
и файл 2.sorted.txt
, содержащий:
1.line-3
2.line-1
2.line-2
2.line-4
2.line-6
3.line-5
основной вывод из comm 1.sorted.txt 2.sorted.txt
:
1.line-1
1.line-2
1.line-3
1.line-4
1.line-6
2.line-1
2.line-2
2.line-4
2.line-6
3.line-5
Для файла script.sed
, содержащего:
/^\t\t/ {
s///
w file.3
d
}
/^\t/ {
s///
w file.2
d
}
/^[^\t]/ {
w file.1
d
}
вы можете запустить приведенную ниже команду и получить желаемый результат следующим образом:
$ comm 1.sorted.txt 2.sorted.txt | sed -f script.sed
$ cat file.1
1.line-1
1.line-2
1.line-4
1.line-6
$ cat file.2
1.line-3
2.line-1
2.line-4
2.line-6
$ cat file.3
2.line-2
3.line-5
$
script работает по:
- совпадающие строки, начинающиеся с 2 вкладок, удаление вкладок, запись строки на
file.3
и удаление строки (так что остальная часть script игнорируется), - совпадающие строки, начинающиеся с 1 вкладки, удаление вкладки, запись строки на
file.2
и удаление строки (так что остальная часть script игнорируется), - совпадающие строки, которые не начинаются с вкладки, записывая строку на
file.1
и удаляя строку.
Операции совпадения и удаления на шаге 3 больше для симметрии, чем что-либо еще; они могут быть опущены (оставив только w file.1
), и этот script будет работать одинаково. Однако см. Ниже script3.sed
для дальнейшего обоснования сохранения симметрии.
Как написано, для этого требуется GNU sed
; BSD sed
не распознает экраны \t
. Очевидно, что файл можно записать с фактическими вкладками вместо обозначения \t
, а затем BSD sed
в порядке с script.
Можно заставить все работать в командной строке, но это неудобно (и это вежливо об этом). Используя Bash ANSI C Quoting, вы можете написать:
$ comm 1.sorted.txt 2.sorted.txt |
> sed -e $'/^\t\t/ { s///\n w file.3\n d\n }' \
> -e $'/^\t/ { s///\n w file.2\n d\n }' \
> -e $'/^[^\t]/ { w file.1\n d\n }'
$
который записывает каждый из трех "абзацев" script.sed
в отдельный параметр -e
. Команда w
суетлива; он ожидает имя файла и только имя файла после него в той же строке script, следовательно, использование \n
после имен файлов в script. Есть пробелы, которые могут быть устранены, но симметрия становится яснее с изображением. И использование файла -f script.sed
, вероятно, проще - это, безусловно, метод, который стоит знать, поскольку он может избежать проблем, когда sed
script должен работать с одинарными, двойными и обратными кавычками, что затрудняет запись script в командной строке Bash.
Наконец, если два файла могут содержать строки, начинающиеся с вкладок, этот метод требует более грубой силы, чтобы заставить его работать. Одно из вариантов использует Bash замещение процесса, чтобы добавить префикс перед строками в файлах, а затем постобработку sed
script удаляет префиксы перед записью в выходные файлы.
script3.sed
(при замене вкладок на 8 пробелов) - обратите внимание, что на этот раз в третьем абзаце есть подстановка s///
(d
по-прежнему необязательна, но также может быть включена):
/^ X/ {
s///
w file.3
d
}
/^ X/ {
s///
w file.2
d
}
/^X/ {
s///
w file.1
d
}
И в командной строке:
$ comm <(sed 's/^/X/' 1.sorted.txt) <(sed 's/^/X/' 2.sorted.txt) |
> sed -f script3.sed
$
Для одних и тех же входных файлов это производит тот же вывод, но добавив и удалив X
в начале каждой строки, код не изменит порядок сортировки данных и будет обрабатывать ведущие вкладки, если они присутствовали.
Вы также можете легко писать решения, которые используют Perl или Awk, и этим даже не нужно использовать comm
(и их можно заставить работать с несортированными файлами при условии, что файлы вписываются в память).