แปลงไฟล์ข้อความของบิตเป็นไฟล์ไบนารี


12

ฉันมีไฟล์ที่instructions.txtมีเนื้อหา:

00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

ฉันจะสร้างไฟล์ไบนารีinstructions.binของข้อมูลเดียวกันinstructions.txtได้อย่างไร กล่าวอีกนัยหนึ่ง.binไฟล์ควรเป็น 192 บิตเดียวกันที่อยู่ใน.txtไฟล์โดยมี 32 บิตต่อบรรทัด ฉันใช้ทุบตีบน Ubuntu Linux ฉันพยายามใช้xxd -b instructions.txtแต่ผลลัพธ์นั้นยาวกว่า 192 บิต

คำตอบ:


6

oneliner เพื่อแปลงสตริง 32 บิตของสตริงและศูนย์ให้เป็นไบนารีที่สอดคล้องกัน:

$ perl -ne 'print pack("B32", $_)' < instructions.txt > instructions.bin

มันทำอะไร:

  • perl -neจะวนซ้ำผ่านแต่ละบรรทัดของไฟล์อินพุตที่ให้ไว้ใน STDIN ( instructions.txt)
  • pack("B32", $_)จะรับรายการสตริง 32 บิต ( $_ซึ่งเราเพิ่งอ่านจาก STDIN) และแปลงเป็นค่าไบนารี่ (คุณสามารถใช้"b32"ถ้าคุณต้องการเรียงลำดับบิตในแต่ละไบต์แทนลำดับบิตจากมากไปหาน้อยดูperldoc -f packรายละเอียดเพิ่มเติม)
  • print จะส่งออกที่แปลงค่าเป็น STDOUT ซึ่งเราจะเปลี่ยนเส้นทางไปยังไฟล์ไบนารีของเรา instructions.bin

ตรวจสอบ:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....

8

การเพิ่ม-rตัวเลือก (โหมดย้อนกลับ) ไปใช้งานxxd -bไม่ได้ตามที่ต้องการจริง ๆ เพราะ xxd ไม่สนับสนุนการรวมค่าสถานะสองค่า-bนี้ คุณต้องแปลงบิตเป็นฐานสิบหกก่อน ตัวอย่างเช่นนี้:

( echo 'obase=16;ibase=2'; sed -Ee 's/[01]{4}/;\0/g' instructions.txt ) | bc | xxd -r -p > instructions.bin

คำอธิบายแบบเต็ม:

  • ส่วนในวงเล็บสร้างbcสคริปต์ โดยจะตั้งค่าฐานอินพุตเป็นไบนารี (2) และฐานเอาต์พุตเป็นเลขฐานสิบหก (16) หลังจากนั้นsedคำสั่งจะพิมพ์เนื้อหาของinstructions.txtด้วยเครื่องหมายอัฒภาคระหว่างแต่ละกลุ่มของ 4 บิตซึ่งสอดคล้องกับ 1 ฐานสิบหกหลัก ผลลัพธ์จะถูกส่งไปbcยัง
  • เซมิโคลอนเป็นตัวคั่นคำสั่งbcดังนั้นสคริปต์ทั้งหมดจะถูกพิมพ์ออกมาทุกจำนวนเต็มกลับออกมา (หลังจากการแปลงฐาน)
  • การส่งออกของเป็นลำดับของตัวเลขฐานสิบหกซึ่งสามารถแปลงเป็นไฟล์ที่มีตามปกติbcxxd -r -p

เอาท์พุท:

$ hexdump -Cv instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018
$ xxd -b -c4 instructions.bin
00000000: 00000000 00000000 00000000 00010011  ....
00000004: 00000010 11010001 00100000 10000011  .. .
00000008: 00000000 01110011 00000010 10110011  .s..
0000000c: 00000000 01110011 00000100 00110011  .s.3
00000010: 00000000 01110011 01100100 10110011  .sd.
00000014: 00000000 00000000 00000000 00010011  ....

ขออภัยยังมีข้อผิดพลาด endianness ในสิ่งนี้ ทำงานเกี่ยวกับการซ่อมมัน!
nomadictype

1
ที่จริงแล้วก็โอเค ฉันสับสนก่อนหน้านี้โดยใช้ความกว้างเอาต์พุตที่ไม่ถูกต้องในคำสั่ง xxd สุดท้าย
nomadictype

1
ผมได้ทดสอบสคริปต์และการทำงาน (standard_in) 1: syntax errorแต่เอาท์พุท: คุณช่วยอธิบายสิ่งที่syntax errorกล่าวถึงหรือสาเหตุที่เกิดขึ้นได้หรือไม่ สิ่งนี้เกิดขึ้นกับเครื่องของคุณด้วยหรือไม่?
dopamane

2

คำตอบเดิมของฉันไม่ถูกต้อง - xxdไม่สามารถยอมรับ-pหรือ-rด้วย-b...

ระบุว่าคำตอบอื่น ๆ นั้นสามารถใช้การได้และในความสนใจของ " วิธีอื่น " วิธีการดังต่อไปนี้:

อินพุต

$ cat instructions.txt
00000000000000000000000000010011
00000010110100010010000010000011
00000000011100110000001010110011
00000000011100110000010000110011
00000000011100110110010010110011
00000000000000000000000000010011

เอาท์พุต

$ hexdump -Cv < instructions.bin
00000000  00 00 00 13 02 d1 20 83  00 73 02 b3 00 73 04 33  |...... ..s...s.3|
00000010  00 73 64 b3 00 00 00 13                           |.sd.....|
00000018

ไปป์ไลน์:

cat instructions.txt \
    | tr -d $'\n' \
    | while read -N 4 nibble; do 
        printf '%x' "$((2#${nibble}))"; \
      done \
    | xxd -r -p \
    > instructions.bin
  • cat - ไม่จำเป็น แต่ใช้เพื่อความชัดเจน
  • tr -d $'\n' - ลบบรรทัดใหม่ทั้งหมดออกจากอินพุต
  • read -N 4 nibble- อ่านว่า 4 ×ตัวอักษรลงในnibbleตัวแปร
  • printf '%x' "$((2#${nibble}))" แปลงแทะจากไบนารี่ถึง 1 ×ฐานสิบหกตัวอักษร
    • $((2#...)) - แปลงค่าที่กำหนดจากฐาน 2 (ไบนารี) เป็นฐาน 10 (ฐานสิบ)
    • printf '%x' - จัดรูปแบบค่าที่กำหนดจากฐาน 10 (ฐานสิบ) ถึงฐาน 16 (เลขฐานสิบหก)
  • xxd -r -p- reverse ( -r) การดัมพ์ธรรมดา ( -p) - จากเลขฐานสิบหกไปเป็นไบนารี่ดิบ

งูหลาม:

python << EOF > instructions.bin
d = '$(cat instructions.txt | tr -d $'\n')'
print(''.join([chr(int(d[i:i+8],2)) for i in range(0, len(d), 8)]))
EOF
  • unquoted heredoc ( << EOF) ถูกนำมาใช้เพื่อให้ได้เนื้อหาลงในรหัสหลาม
    • สิ่งนี้ไม่มีประสิทธิภาพถ้าอินพุตมีขนาดใหญ่
  • catและtr- ใช้เพื่อรับอินพุต (หนึ่งบรรทัด) ที่สะอาด
  • range(0, len(d), 8)- รับรายการตัวเลขตั้งแต่ 0 ถึงจุดสิ้นสุดของสตริงd, ก้าว 8 ×ตัวอักษรในเวลา
  • chr(int(d[i:i+8],2))- แปลงชิ้นปัจจุบัน ( d[i:i+8]) จากไบนารี่เป็นทศนิยม ( int(..., 2)) จากนั้นเป็นอักขระดิบ ( chr(...))
  • [ x for y in z]- ความเข้าใจในรายการ
  • ''.join(...) - แปลงรายการของตัวละครเป็นสตริงเดียว
  • print(...) - พิมพ์

1
หมายเหตุ: ในเชลล์จำนวนมาก|ที่ส่วนท้ายของบรรทัดทำงานเหมือนกับแบ็กสแลช: คำสั่งยังคงบรรทัดถัดไป วิธีนี้คุณสามารถกำจัดแบ็กสแลชสักสองสามตัวได้ ฉันไม่แน่ใจว่าการใช้สัญลักษณ์ไปป์หลังจาก LF เป็นคำตัดสินของคุณหรือไม่ ฉันกำลังพูดถึงวิธีอื่นในกรณีที่คุณไม่รู้
Kamil Maciorowski

1
ฉันไม่รู้ขอขอบคุณ! ฉันชอบแบ่งท่อเป็นเส้นตรรกะและมีท่อ|(หรือเปลี่ยนเส้นทาง>ผู้ประกอบการบูลีน&&ฯลฯ ... ) ที่ด้านหน้าอย่างชัดเจนสำหรับการมองเห็น / ความชัดเจน ... อาจเป็นสิ่งที่โวหาร / การตั้งค่า
Attie

1
หลังจากความคิดบางอย่างฉันอาจเริ่มใช้รูปแบบนี้เพราะเราสามารถบอกได้ว่าทั้งสองสายเชื่อมต่อกันโดยการตรวจสอบใด ๆของพวกเขา หาก|อยู่ท้ายสุดบรรทัดถัดไปอาจดูเหมือนคำสั่งสแตนด์อะโลนอาจทำให้เกิดความสับสน นี่คือเหตุผลที่ฉันคิดว่าสไตล์อาจเป็นการตัดสินใจของคุณอย่างชาญฉลาด
Kamil Maciorowski

เยี่ยมมากให้ฉันได้รู้ว่ามันจะเป็นอย่างไร :-)
Attie

1
มันจะดี :)
Kamil Maciorowski

1

คุณอาจลองโพสต์สิ่งนี้บนเว็บไซต์ CodeGolf SE แต่นี่เป็นเวอร์ชั่น Python ทางเลือกของฉัน (สำหรับการแข่งขันที่ท้าทาย):

python -c "import sys,struct;[sys.stdout.buffer.write(struct.pack('!i',int(x,2)))for x in sys.stdin]" \
< input.txt > output.bin

สมมติว่าinput.txtมีข้อมูลของคุณและมีการจัดรูปแบบเป็น 32 อักขระต่อบรรทัด

ใช้structแพ็คเกจPython 3 และเขียน / อ่านเพื่อ stdin / out (ใน Python 2 มันจะสั้นกว่านี้)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.