Как побитно инвертировать файл в linux shell

Мне понадобилось изготовить файлик довольно большого размера - 16Кбайт, заполненный одними нулями и одними единичками. Но не смоволами юникода 0 и 1, а битами.
Итак. Получить нолики просто:

dd if=/dev/zero of=./16384_zeroes count=16384 bs=1

Проверить, что там побитовые нолики можно так:

$ xxd -b 16384_zeroes
00000000: 00000000 00000000 00000000 00000000 00000000 00000000  ......
00000006: 00000000 00000000 00000000 00000000 00000000 00000000  ......
0000000c: 00000000 00000000 00000000 00000000 00000000 00000000  ......
00000012: 00000000 00000000 00000000 00000000 00000000 00000000  ......
...
00003ffc: 00000000 00000000 00000000 00000000                    ....

Инвертировать побитово файл можно с помощью утилиты tr примерно так:

LC_ALL=C tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' < 16384_zeroes > 16384_ones

Зачем мне такое надо

А дальше я буду заливать этот файлик на флешку. У меня есть подозрения, что флеха (карточка Micro SD HC Kingston 16Gb SDC4 ) портит данные. Вот мы это и проверим.
Итак, смотрим сколько байтов у нас на флехе:

fdisk -l /dev/sdc
Disk /dev/sdc: 14.42 GiB, 15472787456 bytes, 30220288 sectors

То есть нам надо сделать файлик длинной 15472787456 байт, посчитать его контрольную сумму, залить его на флеху, слить обратно и снова посчитать контрольную сумму. Если всё в порядке - сумма сойдется.
Будем создавать файлик сразу блоками по 1М, чтобы было быстро. Посчитаем сколько раз по 1М поместится на флехе:

$ echo $(( 15472787456/1048576 ))
14756

Теперь делаем маленький скриптик:

rm -f ./16G_ones.img; for count in {1..14756}; do dd if=/dev/zero count=1 bs=1M | LC_ALL=C tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' >> ./16G_ones.img; echo $count; done

Он создаст нам файлик, в котором будет ровно 15472787456 байт, в которых все биты - единички!
Зальем его на флеху:

dd if=./16G_ones.img of=/dev/sdc bs=16384 count=944384

А дальше считаем флеху и проверим контрольные суммы:

sha1sum -b ./16G_ones.img
c068f9b373027daaabc6214d401da9341e5fa545 *./16G_ones.img

dd if=/dev/sdc of=./sdc_ones bs=16384 count=944384
sha1sum -b ./sdc_ones 
d2c42aa3c9b5be47e3fc5ef8aced8f9d867d3aea *./sdc_ones

rm -f ./sdc_ones
dd if=/dev/sdc of=./sdc_ones bs=16384 count=944384
sha1sum -b ./sdc_ones 
25bac255911597a5962598e5c817e208baa63c72 *./sdc_ones

rm -f ./sdc_ones
dd if=/dev/sdc of=./sdc_ones bs=16384 count=944384
sha1sum -b ./sdc_ones 
984396d75505063aaef7f23a40f337f7a70b5294 *./sdc_ones

В результате - видно, что каждый раз при считывании контрольная сумма оказывается разная!!
Вывод - карточка битая! При этом - в логах ядра никаких ошибок чтения!

Как обойтись без файлика

Инвертируем нолики в единички налету и льем на диск:

export LC_ALL=C && dd if=/dev/zero bs=16384 count=3897983 | tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' | dd of=/dev/sdc bs=16384

Посчитаем SHA1, который должен быть:

export LC_ALL=C && dd if=/dev/zero bs=16384 count=3897983 | tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' | sha1sum -b -
9cee0b471cd582196b1c9fddf780186e69c526be *-

А теперь посчитаем фактический SHA1:

dd if=/dev/sdc bs=16384 count=3897983 | sha1sum -b -
9cee0b471cd582196b1c9fddf780186e69c526be *-

На новой флехе всё совпадает.
Вот скрипт для проверки флешки. Сначала скрипт заливает весь диск единичками, проверяет, потом - заливает нулями и проверяет:

#!/bin/bash 

disk=$1
disk_size=`blockdev --getsize64 $disk`
block_size=32768
count=$(( $disk_size / $block_size ))
red=`tput setaf 1`
green=`tput setaf 2`
reset=`tput sgr0`

echo "Disk: ${disk}, Disk Size in bytes: ${disk_size}, Blocks count: ${count}"
echo "Calculating reference sha1sum with ones..."
ref_csum=`export LC_ALL=C && dd if=/dev/zero bs=$block_size count=$count status=progress | tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' | sha1sum -b -`
echo "Reference sha1sum with ones: $ref_csum"

echo "Filling disk with ones..."
export LC_ALL=C && dd if=/dev/zero bs=$block_size count=$count status=progress | tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' | dd of=$disk bs=$block_size 
echo "Flushing buffers to disks..."
sync
sync
echo 3 > /proc/sys/vm/drop_caches 

echo "Calculating sha1sum of the disk content..."
fact_csum=`dd if=$disk bs=$block_size count=$count status=progress | sha1sum -b -`
echo "Fact disk content sha1sum checksum: $fact_csum"

if [ "$ref_csum" = "$fact_csum" ]; then 
  echo "Check with ones passed... ${green}Disk is OK!${reset}"
else
  echo "Check with ones failed... ${red}Disk is BAD!${reset}"
fi

echo "Calculating reference sha1sum with zeroes..."
ref_csum=`dd if=/dev/zero bs=$block_size count=$count status=progress | sha1sum -b -`
echo "Reference sha1sum with zeroes: $ref_csum"

echo "Filling disk with zeroes..."
dd if=/dev/zero of=$disk bs=$block_size count=$count status=progress
echo "Flushing buffers to disks..."
sync
sync
echo 3 > /proc/sys/vm/drop_caches 

echo "Calculating sha1sum of the disk content..."
fact_csum=`dd if=$disk bs=$block_size count=$count status=progress | sha1sum -b -`
echo "Fact disk content sha1sum checksum: $fact_csum"

if [ "$ref_csum" = "$fact_csum" ]; then 
  echo "Check with ones passed... ${green}Disk is OK!${reset}"
else
  echo "Check with ones failed... ${red}Disk is BAD!${reset}"
fi
Enter your comment. Wiki syntax is allowed:
 
  • linux_faq/bash_bits_operations.txt
  • Last modified: 2020/12/08 21:09
  • by admin