Приглашение rm при удалении незаписываемых файлов

Это запрошенное однострочное решение (для последних оболочек, которые имеют «подстановку процесса»):

grep -o "ef be ad de" <(hexdump -v -e '/1 "%02x "' infile.bin) | wc -l

Если «подстановка процесса» <(…) недоступна, просто используйте grep как filter:

hexdump -v -e '/1 "%02x "' infile.bin  | grep -o "ef be ad de" | wc -l

Ниже приводится подробное описание каждой части решения.

Байтовые значения из шестнадцатеричных чисел:

Первую проблему легко решить:

Эти escape-последовательности \ Xnn работают только в оболочке Fish.

Измените верхний X на нижний x и используйте printf (для большинства оболочек):

$ printf -- '\xef\xbe\xad\xde'

Или используйте:

$ /usr/bin/printf -- '\xef\xbe\xad\xde'

Для тех оболочек, которые предпочитают не реализовывать представление '\ x'.

Конечно, преобразование шестнадцатеричного числа в восьмеричное будет работать (почти) в любой оболочке:

$ "$sh" -c 'printf '\''%b'\'' "$(printf '\''\\0%o'\'' $((0xef)) $((0xbe)) $((0xad)) $((0xde)) )"'

Где «$ sh» - любая (разумная) оболочка. Но правильно процитировать его довольно сложно.

Двоичные файлы.

Наиболее надежным решением является преобразование файла и последовательности байтов (обоих) в некоторую кодировку, которая не имеет проблем с нечетными значениями символов, например (новая строка) 0x0A или (нулевой байт) 0x00 . И тем и другим довольно сложно правильно управлять с помощью инструментов, разработанных и адаптированных для обработки «текстовых файлов».

Преобразование, подобное base64, может показаться допустимым, но оно представляет проблему, заключающуюся в том, что каждый входной байт может иметь до трех выходных представлений в зависимости от того, является ли он первым, вторым или третьим байтом позиции mod 24 (биты).

$ echo "abc" | base64
YWJjCg==

$ echo "-abc" | base64
LWFiYwo=

$ echo "--abc" | base64
LS1hYmMK

$ echo "---abc" | base64        # Note that YWJj repeats.
LS0tYWJjCg==

Шестнадцатеричное преобразование.

Вот почему наиболее надежным преобразованием должно быть преобразование, которое начинается на границе каждого байта, как в простом HEX-представлении.
Мы можем получить файл с шестнадцатеричным представлением файла любым из следующих инструментов:

$ od -vAn -tx1 infile.bin | tr -d '\n'   > infile.hex
$ hexdump -v -e '/1 "%02x "' infile.bin  > infile.hex
$ xxd -c1 -p infile.bin | tr '\n' ' '    > infile.hex

Последовательность байтов для поиска в данном случае уже шестнадцатеричная.
:

$ var="ef be ad de"

Но это также может быть преобразовано. Пример передачи шестнадцатеричного-двоичного-шестнадцатеричного цикла туда и обратно:

$ echo "ef be ad de" | xxd -p -r | od -vAn -tx1
ef be ad de

Строка поиска может быть установлена ​​из двоичного представления. Любой из трех представленных выше вариантов od, hexdump или xxd эквивалентен. Просто убедитесь, что вы включили пробелы, чтобы обеспечить совпадение на границах байтов (сдвиг на полубайты не разрешен):

$ a="$(printf "\xef\xbe\xad\xde" | hexdump -v -e '/1 "%02x "')"
$ echo "$a"
ef be ad de

Если двоичный файл выглядит следующим образом:

$ cat infile.bin | xxd
00000000: 5468 6973 2069 7320 efbe adde 2061 2074  This is .... a t
00000010: 6573 7420 0aef bead de0a 6f66 2069 6e70  est ......of inp
00000020: 7574 200a dead beef 0a66 726f 6d20 6120  ut ......from a 
00000030: 6269 0a6e 6172 7920 6669 6c65 2e0a 3131  bi.nary file..11
00000040: 3232 3131 3232 3131 3232 3131 3232 3131  2211221122112211
00000050: 3232 3131 3232 3131 3232 3131 3232 3131  2211221122112211
00000060: 3232 0a

Затем простой поиск с помощью grep выдаст список совпадающих последовательностей:

$ grep -o "$a" infile.hex | wc -l
2

Одна строка?

Все это можно выполнить в одной строке:

$ grep -o "ef be ad de" <(xxd -c 1 -p infile.bin | tr '\n' ' ') | wc -l

Например, для поиска 11221122 в том же файле потребуются следующие два шага:

$ a="$(printf '11221122' | hexdump -v -e '/1 "%02x "')"
$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ') | wc -l
4

Чтобы "увидеть" совпадения:

$ grep -o "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')
3131323231313232
3131323231313232
3131323231313232
3131323231313232

$ grep "$a" <(xxd -c1 -p infile.bin | tr '\n' ' ')

… 0a 3131323231313232313132323131323231313232313132323131323231313232 313132320a


Буферизация

Есть опасения, что grep будет буферизовать весь файл, и, если файл большой, создаст большой . Для этого мы можем использовать небуферизованное решение sed:

a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin  | 
    sed -ue 's/\('"$a"'\)/\n\1\n/g' | 
        sed -n '/^'"$a"'$/p' |
            wc -l

Первый sed не буферизован ( -u ) и используется только для вставки двух новых строк в поток для каждой соответствующей строки. Второй sed будет печатать только (короткие) совпадающие строки. Wc -l подсчитает совпадающие строки.

Это приведет к буферизации только некоторых коротких строк. Соответствующая строка (строки) во втором sed. Это должно быть довольно мало используемых ресурсов.

Или, что несколько сложнее для понимания, но та же идея в одном sed:

a='ef be ad de'
hexdump -v -e '/1 "%02x "' infile.bin  |
    sed -u '/\n/P;//!s/'"$a"'/\n&\n/;D' |
        wc -l
1
09.04.2016, 09:56
0 ответов

Теги

Похожие вопросы