Mengedit stream biner yang mengandung byte '\ x00'

8

Menggunakan alat shell saja, bagaimana bisa aliran biner yang mengandung NULLs (0x00 karakter) diedit menjaga 0x00 karakter dalam aliran output?

Hasil edit perlu mengganti char pada posisi yang ditentukan untuk char lain (dalam contoh berikut oleh char '|'), seperti:

dd ibs=1 skip=$offset count=$reglen status=none if=$ARQ |
        sed 's/./\|/2' |
        sed 's/./\|/5' #| more replacements....

Tapi sed menghapus semua karakter '\ 0x00' sebelum penggantian.

EDIT - Demonstrasi perilaku sed di lingkungan saya menggunakan tes @ George Vasiliou:

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | od -t x1
0000000 6c 69 6e 65 41 00 6c 69 6e 65 42 00 6c 69 6e 65
0000020 43 00
0000022

$ echo -e "lineA\nlineB\nlineC" | tr '\n' '\0' | sed 's/./|/5' | od -t x1
0000000 6c 69 6e 65 7c 6c 69 6e 65 42 6c 69 6e 65 43
0000017

Lingkungan saya adalah AIX 7.1 dan sed yang tidak ada versi gnu.

Luciano
sumber

Jawaban:

10

sedadalah utilitas teks . Ia bekerja dengan baris teks (urutan karakter non-NUL (bukan byte) dengan panjang terbatas dibatasi oleh karakter baris baru).

Jika Anda ingin mengubah 2 nd dan 5 th byte dari urutan byte, tidak akan bekerja untuk beberapa alasan:

  • sedbekerja pada teks. Jika input berisi NUL karakter, tidak berakhir dengan karakter baris baru, memiliki lebih dari LINE_MAX byte di antara dua karakter baris baru, berisi urutan byte yang tidak membentuk karakter yang valid, tergantung pada sedimplementasinya, itu tidak akan berfungsi pada semua. (perhatikan bahwa GNU sedtidak memiliki banyak dari batasan itu).
  • bahkan jika input biner itu terjadi untuk membentuk teks yang valid, .cocok dengan karakter, bukan byte, jadi mungkin cocok dengan lebih dari satu byte.
  • karena kode sed dijalankan untuk setiap baris input, itu akan mengubah karakter kedua dan kelima dari setiap baris, bukan seluruh input.

Untuk memperlakukan input sebagai array byte yang arbitrer (tanpa batasan byte NUL, atau batasan panjang), Anda sebaiknya menggunakan perl:

 dd.... | perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}'

Contoh:

$ printf 'a\0b\0cd' |
>   perl -0777 -pe 'for $o (1, 4) {substr($_, $o, 1) = "|"}' |
>   od -Ax -tx1 -tc
000000  61  7c  62  00  7c  64
         a   |   b  \0   |   d
000006

Atau Anda bisa menggunakan representasi teks menengah, seperti menggunakan vim's xxdhelper:

dd... | xxd -p | sed '1s/../7c/2;1s/../7c/5' | xxd -p -r

xxd -pmemberikan dump hex dengan 60 karakter per baris secara default. Di atas kami mengganti hex 2-digit kedua dan kelima dari baris pertama 7c, nomor untuk ASCII |.

Stéphane Chazelas
sumber
Terima kasih. Saya sedang membangun solusi menggunakan xxd. Bagus ! Kedua solusi tersebut bekerja di AIX.
Luciano
1

Apakah kamu yakin dengan tes sederhana ini sepertinya tidak terjadi dalam kasus saya (gnu sed 4.2.2)

$ echo -e "lineA\nlineB\nlineC"
lineA
lineB
lineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0'
lineAlineBlineC
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/5'
line|lineBlineC
# Verification if the nulls are still there:
$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/5' |tr '\0' '\n'                                                                                                
line|
lineB
lineC

Dengan pengujian lebih lanjut, null akan hilang jika Anda mengganti karakter ke-6 dalam pengujian saya (posisi nol):

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/6' |tr '\0' '\n'
lineA|lineB 
lineC

$ echo -e "lineA\nlineB\nlineC" |tr '\n' '\0' |sed 's/./|/7' |tr '\0' '\n'
lineA
|ineB           
lineC 
George Vasiliou
sumber
@Luciano Lihat pembaruan
George Vasiliou
Lihatlah hasil edit saya
Luciano
@Luciano, saya juga mencoba dengan sed --posix yang sesuai dengan manual saya menonaktifkan semua ekstensi GNU, tetapi masih ada byte nol yang hadir ....
George Vasiliou
Saya mencoba sed di Linux, dan ya kelihatannya bisa berfungsi. Tapi saya harus membuatnya bekerja di AIX.
Luciano
1
@Luciano, Tentu, saya bisa mengerti ini ... Sayangnya saya tidak punya AIX untuk membantu Anda, dan sejauh yang saya tahu tampaknya tidak ada AIX Shells yang bisa dimainkan secara online ... Saya yakin jawaban dari Tuan Chazelas akan membantu Anda.
George Vasiliou
0

Coba bbe - sed clone untuk stream biner: https://sourceforge.net/projects/bbe/

pengguna280267
sumber
Bisakah Anda menambahkan beberapa detail pendukung, seperti bagaimana pengguna di lingkungan AIX mereka mungkin menggunakannya? Juga, perhatikan bahwa pertanyaannya mengatakan "Menggunakan alat shell saja", sehingga mereka mungkin dibatasi dari mengkompilasi / menginstal alat tambahan,
Jeff Schaller
Apakah Anda yakin menautkan ke alat yang tepat? Tautan Anda masuk ke proyek "Enkripsi Berbasis Blok alias 2Bx4Bx2B" yang terakhir diperbarui pada 2013
Ale