Вопрос или проблема
Я хочу использовать инструмент командной строки для сравнения файлов и нужен номер строки перед строкой вывода, с помощью которой я мог бы перейти к различию в строке, потому что я использую инструмент, который понимает, куда переходить, если строка начинается так :номер-строки: содержание строки
Итак, я попробовал diff
, и, прочитав документацию, кажется, что это может быть возможно:
-D, --ifdef=NAME вывод объединенного файла с различиями `#ifdef NAME'
--GTYPE-group-format=GFMT форматировать группы входных данных GTYPE с помощью GFMT
--line-format=LFMT форматировать все входные строки с помощью LFMT
--LTYPE-line-format=LFMT форматировать входные строки LTYPE с помощью LFMT
Эти опции форматирования обеспечивают тонкий контроль над выводом
diff, обобщая -D/--ifdef.
LTYPE - это `old', `new' или `unchanged'. GTYPE - это LTYPE или `changed'.
GFMT (только) может содержать:
%< строки из FILE1
%> строки из FILE2
%= общие строки для FILE1 и FILE2
%[-][WIDTH][.[PREC]]{doxX}LETTER спецификация стиля printf для буквы LETTER
Буквы следующие для новой группы, строчные для старой группы:
F номер первой строки
L номер последней строки
N количество строк = L-F+1
E F-1
M L+1
%(A=B?T:E) если A равно B, то T иначе E
LFMT (только) может содержать:
%L содержимое строки
%l содержимое строки, исключая любой завершающий перевод строки
%[-][WIDTH][.[PREC]]{doxX}n спецификация стиля printf для номера входной строки
Both GFMT and LFMT may contain:
%% %
%c'C' один символ C
%c'\OOO' символ с восьмеричным кодом OOO
C символ C (остальные символы представляют сами себя)
но нет примера или объяснения по этому сложному переключателю.
Возможно ли получить такой вывод от diff
? Если да, то как?
Да, это возможно. При использовании этих опций по умолчанию просто выводится каждая строка. Это очень многословно и не то, что вам нужно.
diff --unchanged-line-format=""
устранит неизмененные строки, так что сейчас будут выводиться только старые и новые строки.
diff --unchanged-line-format="" --new-line-format=":%dn: %L"
теперь будет показывать новые строки с префиксом :<номерстроки>:
и пробелом, но все еще выводит старые строки. Если предположить, что вы хотите их устранить,
diff --unchanged-line-format="" --old-line-format="" --new-line-format=":%dn: %L"
Если вы хотите, чтобы выводились старые строки вместо новых, поменяйте их местами.
Иногда картина или пример стоят 1000 слов. Я составил следующий конвейер, чтобы “сравнить” два дампа MySQL (структуры) на основе ответа wnoise
(пожалуйста, отдайте все голоса в пользу wnoise
).
Пример побочных номеров строк:
diff --unchanged-line-format="" --old-line-format="%dn: %L " --new-line-format="| %dn: %L" \
./20220202-msqldump.sql ./20221130-msqldump.sql |
awk -e' /^[[:digit:]]+: )/{ previous = $0; next; } { print previous $0 }' |
grep -v -e"ENGINE=InnoDB AUTO_INCREMENT="
К сожалению, я обнаружил, что опция diff
для выполнения: --side-by-side
не поддерживается с опциями формата строки.
Исключив строки AUTO_INCREMENT, у меня осталось всего две различия: дата и т.д.
Без фильтра grep
вывод выглядит следующим образом:
5127: ) ENGINE=InnoDB AUTO_INCREMENT=340 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; | 5105: ) ENGINE=InnoDB AUTO_INCREMENT=271 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
5150: ) ENGINE=InnoDB AUTO_INCREMENT=895 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; | 5128: ) ENGINE=InnoDB AUTO_INCREMENT=763 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
5170: ) ENGINE=InnoDB AUTO_INCREMENT=1371 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; | 5148: ) ENGINE=InnoDB AUTO_INCREMENT=1173 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Обратите внимание, что номера строк не совпадают. Я использовал meld
, чтобы убедиться, что все выстраивается в линию.
Ответ или решение
Теория
Одной из классических задач в области информационных технологий является сравнение файлов, с целью определения различий между двумя версиями текста. Инструмент diff
является мощным инструментом командной строки, который позволяет пользователям выявлять различия между текстовыми файлами. Однако стандартное использование diff
может не всегда соответствовать специфическим требованиям пользователя, например, если необходимо указать номер строки перед каждой найденной разницей. В этом случае форматирование вывода с помощью --line-format
и подобных опций дает возможность настроить вывод в нужном формате.
Пример
Для получения вывода от diff
, в котором различия будут сопровождаться номерами строк, можно использовать следующие команды:
-
Без вывода неизмененных строк:
diff --unchanged-line-format=""
Эта команда исключает из вывода строки, которые остались без изменений.
-
Форматирование новых строк:
diff --unchanged-line-format="" --new-line-format=":%dn: %L"
В этом варианте новые строки отображаются с их номерами, начинающимися с
:<номер строки>:
и следом идет содержимое строки. -
Исключение старых строк и вывод только новых:
diff --unchanged-line-format="" --old-line-format="" --new-line-format=":%dn: %L"
Это окончательная команда выводит только новые строки, где каждая строка предваряется номером.
Применение
Применение вышеприведенных команд полезно, когда необходимо интегрировать вывод diff
с другими инструментами или процессами анализа, которые могут использовать информацию о номерах строк, чтобы переходить непосредственно к местам различий. Например, если у вас есть инструмент, который может интерпретировать формат :<номер строки>: содержимое строки
, то это позволит вам быстро и эффективно перейти к соответствующей строке в файле.
Пример из реального мира: сравнение двух дампов структуры баз данных MySQL для выявления изменений. С помощью diff
и командного конвейера, включающего awk
и grep
, можно создать фильтр, который отбрасывает строки с ненужной информацией, такой как AUTO_INCREMENT, и сосредотачивается только на релевантных различиях.
Таким образом, используемые методы позволяют персонализировать вывод diff
, предоставляя гибкость, необходимую для решения сложных задач и интеграции с другими системами и инструментами.