Как проверить, является ли file1 префиксом file2?

13

У меня есть два файла с размерами 124665 и 124858 в байтах, и я хочу проверить, является ли file1 префиксом file2 или нет.

творог
источник

Ответы:

11

Предположим, у вас есть размер file1переменной FILE1_SZи ваша headреализация поддерживает (нестандартную) -cопцию:

if head -c "$FILE1_SZ" file2 | cmp -s - file1; then
    echo "file1 is a prefix of file2"
else
    echo "file1 is not a prefix of file2"
fi
Джозеф Р.
источник
@ StéphaneChazelas Не могли бы вы объяснить, почему cmpбыло бы лучше, чем diffздесь?
Джозеф Р.
7
Потому cmpчто выполняет простое байтовое сравнение и возвращает, как только обнаружит разницу, а diffтекстовая утилита собирается использовать сложный алгоритм, чтобы показать вам все различия между двумя файлами, которые вас не интересуют.
Стефан Шазелас
12

Если ваша система имеет cmpкоманду из GNU diffutils, то одна из опций

cmp -n 124665 file1 file2

сравнить не более первых 124665 байтов двух файлов и сообщить, отличаются ли они - или, в более общем случае,

cmp -n "$(wc -c < file1)" file1 file2
steeldriver
источник
@StephaneChazelas Я второй угадываю себя здесь, но было бы лучше предложить $(stat -c %s file1)размер в байтах? На wcсамом деле открыть и обработать весь файл, чтобы получить количество байтов?
Steeldriver
2
нет, большинство wcреализаций оптимизирует этот случай и выполнит fstat()(или / и lseek(SEEK_END)), поэтому будет настолько эффективным, насколько это возможно. С другой стороны, это stat -cспецифично для GNU.
Стефан Шазелас
1
Хотя, если вы собираетесь требовать специфичную для GNU cmp, вы можете разумно предположить специфичную для GNU stat.
Бармар
3

GNU cmpможет решить проблему проще:

cmp file1 file2

Есть четыре возможных выхода (исключая какую-то ошибку).

  • Нет вывода: файлы идентичны.

  • cmp: EOF on file1: file1 является префиксом file2.

  • cmp: EOF on file2: file2 является префиксом file1.

  • file1 file2 differ: byte NNN, line MMM: Ни один не является префиксом другого.

К сожалению, это немного неудобно для использования в скрипте, так как эти случаи, кажется, не различаются в коде выхода. Более того, EOF on file1сообщения отправляются в stderr, а file1 file2 differсообщения - в stdout.

Я предполагаю, что другие версии cmpделают что-то подобное, но я не проверял.

Нейт Элдридж
источник
1
cmpэто не команда GNU-only и она не возникла там, она была уже в первой версии Unix в начале 70-х годов. Эта -nопция специфична для GNU.
Стефан Шазелас
Вы могли бы сделатьcmp file1 file2 2>&1 | grep EOF on file1
Дэвид Z
@ StéphaneChazelas: это правда. Я не хотел подразумевать, что cmpэто уникально для GNU, просто GNU cmpбыла единственной версией, которую я пробовал. Я добавил предложение, чтобы уточнить.
Нейт Элдредж
@DavidZ: Да, вы могли бы, но это становится немного менее надежным. Представьте, что вы пытаетесь сделать это с двумя файлами, предоставленными пользователем, и один из них назван, file1а другой назван file12. (Или, что еще хуже, что, если второй файл будет назван EOF on file1?) Решить это с помощью надежного использования cmp, вероятно, гораздо сложнее, чем написать очевидную 5-строчную программу на C ...
Нейт Элдридж
Однако могут быть ситуации, когда программа на С не практична. И это не так сложно сделать достаточно надежным, потому что выходные данные cmpочень сильно ограничены. Использование -xопции on, grepчтобы соответствовать всей строке, позаботится обо всех, кроме самых экзотических случаях (например, новые строки в имени файла).
Дэвид З