Как побитно инвертировать файл в 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
Discussion