Изменитесь только на один бит в файле

Это входит в уничтожать-кольцо, точно так же, как в Emacs. От Readline docuementation GNU:

При использовании команды уничтожения текст сохранен в уничтожать-кольце. Любое количество последовательных уничтожений сохранило весь уничтоженный текст вместе, так, чтобы, когда Вы дергаете его назад, Вы получили все это. Кольцо уничтожения не является конкретной строкой; текст, который Вы уничтожили на ранее введенной строке, доступен, чтобы дергаться назад позже при вводе другой строки.

Источник: http://www.gnu.org/software/bash/manual/html_node/Readline-Killing-Commands.html

Кольцо уничтожения хранится в памяти, выделенной через malloc к символьному указателю. От kill.c из readline источника:

/* Where to store killed text. */
static char **rl_kill_ring = (char **)NULL;

8
15.04.2015, 00:23
6 ответов

Поскольку файл может содержать нули, текстовые фильтры типа sed не будут работать. Но можно использовать язык программирования, который может работать с нулями, например perl или python. Вот решение для Python 3. Это на несколько строк длиннее, чем строго необходимо, для удобочитаемости.

#!/usr/bin/python
"""Toggle the bit at the specified offset.
Syntax: <cmdname> filename bit-offset"""

import sys
fname = sys.argv[1]
# Convert bit offset to bytes + leftover bits
bitpos = int(sys.argv[2])
nbytes, nbits = divmod(bitpos, 8)

# Open in read+write, binary mode; read 1 byte 
fp = open(fname, "r+b")
fp.seek(nbytes, 0)
c = fp.read(1)

# Toggle bit at byte position `nbits`
toggled = bytes( [ ord(c)^(1<<nbits) ] ) 
# print(toggled) # diagnostic output

# Back up one byte, write out the modified byte
fp.seek(-1, 1)  # or absolute: fp.seek(nbytes, 0)
fp.write(toggled)
fp.close()

Сохраните его в файле (например, bitflip), сделайте его исполняемым, и запустите его с именем файла для модификации и смещением в битах. Обратите внимание, что он изменяет файл на месте. Запустите его дважды с одинаковым смещением, и файл будет восстановлен.

3
27.01.2020, 20:11

Наконец-то я нашел решение с XXD и DD .

a=$(xxd -b -l 1 -seek 3 -p a.bin);b=1;echo -e "\x$((${a}^${b}))" | dd of=a.bin bs=1 seek=3 count=1 conv=notrunc

hexdump a.bin     v
0000000 61 39 73 36 36 64 66 38 61 39 73 64 35 36 66 35
0000010 37 61 73 64 37 66 74 75 61 67 73 0a 61 73 64 66

hexdump b.bin     v
0000000 61 39 73 37 36 64 66 38 61 39 73 64 35 36 66 35
0000010 37 61 73 64 37 66 74 75 61 67 73 0a 61 73 64 66

Но это уродливо.

2
27.01.2020, 20:11

Если вы действительно хотите использовать dd, вот мерзость, которая сделает трюк, перевернув самый старший бит в данном байте. Отрегулируйте настройки команды tr для изменения выбранного бита.

# Preparation
finger > original.txt
BYTE=3

# Here we go...
dd if=original.txt bs=1c 2>/dev/null | ( dd bs=1c count=$((BYTE-1)) ; dd bs=1c count=1 | tr '\000-\377' '\200-\377\000-\177' ; dd bs=1c ) 2>/dev/null > flipped.txt

# Demonstrate the difference (byte 3: 67 → e7)
hexdump -C original.txt | head -1
00000000  4c 6f 67 69 6e 20 20 20  20 20 4e 61 6d 65 20 20  |Login     Name  |    
hexdump -C flipped.txt | head -1
00000000  4c 6f e7 69 6e 20 20 20  20 20 4e 61 6d 65 20 20  |Lo.in     Name  |
1
27.01.2020, 20:11

Не думаю, что есть хоть одна команда. Вот простой скрипт, сохраните его как "flipbit":

#!/usr/bin/perl
# Arguments:   byte (starting from 0),  bit (0-7),  filename (otherwise stdin)
$byte = shift(@ARGV);
$bit = shift(@ARGV);
undef $/; 
$file=<>; 
substr($file,$byte,1) = substr($file,$byte,1) ^ chr(1<<$bit); 
print $file;

test:

$ echo abb | ~/bin/flip-bit.pl 2 0 | od -xa
0000000      6261    0a63                                                
       a   b   c  nl                                                

это перевернуло младший бит (0) третьего символа, изменив 'b' на 'c'.

Как команда из одной строки:

perl -e '$byte=shift(@ARGV);$bit=shift(@ARGV);undef $/; $file=<>; substr($file,$byte,1) = substr($file,$byte,1) ^ chr(1<<$bit); print $file'
3
27.01.2020, 20:11

Простое решение с использованием головы , хвоста , xxd . Пример ниже переворачивает младший бит в последнем байте file.bin .

head -c -1 file.bin > flipped.bin
LAST=`tail -c 1 file.bin | xxd -ps`
printf "%02X" $(( $((16#$LAST)) ^ 1 )) | xxd -r -ps >> flipped.bin
0
27.01.2020, 20:11

Вот два perlодин -вкладыша. Первый меняет файл barна -место:

perl -p -0777 -i -e 'substr($_,2,1)^=chr(1<<5)' bar

Второй читает файл fooи записываетbar

perl -p -0777 -e 'substr($_,2,1)^=chr(1<<5)' < foo > bar

Чтобы адаптироваться к вашему приложению :2 выбирает, какой байт :0..file _длина -1, т. е. 2 является третьим байтом. 5 выбирает, какой бит перевернуть :0 -7, т. е. 5 — это 6-й бит. Это будет работать только для файлов, которые помещаются в память.

Пояснение

-pитерация по файлу, печать после каждой итерации
-0777читать весь файл в память на каждой итерации (, поэтому будет только одна итерация)
-eзапустите следующий perl-код внутри цикла
substrвыберите один символ в файле, начиная с индекса 2
^=chrXOR этого символа с 1 сдвинутым 5 раз, т.е. 2^5

Этот ответ является упрощенной версией ответа Тоддкауфмана

.
0
27.01.2020, 20:11

Теги

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