Bagaimana saya bisa menggunakan bit mask pada / dev / zero sehingga saya bisa mendapatkan byte selain nol?
20
Bagaimana saya bisa memakai topeng bit /dev/zerosehingga saya dapat memiliki sumber tidak hanya untuk 0x00 tetapi juga untuk byte antara 0x01 dan 0xFF?
Saya memberikan jawaban untuk pertanyaan ini, tetapi membacanya lagi saya pikir saya salah paham. Apakah Anda ingin menerjemahkan masing 0x00- masing ke nilai tertentu atau ke nilai acak dalam 0x00-0xFFrentang?
kos
1
@kos masing-masing ke nilai tertentu seperti 444444...bukan yang acak
Eduard Florinescu
Jawaban:
18
bashKode berikut ini diatur untuk bekerja dengan byte yang diwakili dalam biner . Namun Anda dapat dengan mudah mengubahnya untuk menangani ocatal , desimal atau hex dengan hanya mengubah radixr nilai 2 untuk 8, 10atau 16masing-masing dan pengaturan b=yang sesuai.
EDIT - Ini menangani berbagai nilai byte: hex 00 - FF (ketika saya menulis 00-7F di bawah ini, saya hanya mempertimbangkan karakter byte tunggal UTF-8).
Jika, misalnya, Anda hanya ingin 4 byte (karakter dalam UTF-8 'ASCII'-only hex 00-7F range) , Anda dapat menyalurkannya ke head :... | head -c4
Output (4 karakter):
~~~~
Untuk melihat output dalam format 8-bit, masukkan ke dalam xxd(atau dump byte 1 dan 0 lainnya *):
mis. b=10000000dan perpipaan ke:... | head -c4 | xxd -b
Apakah Anda bermaksud menulis o=$(printf ...)untuk baris kedua?
jwodder
1
@ jwodder: Tidak, baris kedua benar seperti yang ditunjukkan. The printf pilihan -vmenyebabkan tthe keluaran untuk langsung mengatur variabel bernama segera setelah; dalam hal ini yang nama variabel adalah o(untuk oktal ) - catatan bahwa -vopsi berlaku untuk shell-builtin versi printf(bukan ke / usr / bin / printf versi)
Peter.O
2
@ jwodder Juga, secara umum, -vopsi memastikan variabel diatur ke persis apa yang Anda tentukan. $(...)mengubah output terlebih dahulu. Itulah sebabnya mengapa o=$(printf '\n')tidak akan memiliki efek yang Anda harapkan, sedangkan sebaliknya printf -vo '\n'. (Tidak masalah di sini, karena output di sini adalah dalam bentuk yang tidak terpengaruh oleh transformasi seperti itu, tetapi jika Anda tidak mengetahui -vopsi tersebut, maka ini mungkin berguna untuk diketahui.)
hvd
18
Anda tidak dapat dengan mudah melakukan itu.
Anda mungkin mempertimbangkan untuk menulis modul kernel Anda sendiri yang menyediakan perangkat seperti itu. Saya tidak merekomendasikan itu.
Anda dapat menulis sebuah program C kecil yang menulis aliran tak terbatas dari byte yang sama pada beberapa pipa (atau pada stdout) atau FIFO.
Anda dapat menggunakan tr (1) untuk membaca /dev/zerodan menerjemahkan setiap 0 byte ke sesuatu yang lain.
Anda bisa menggunakan mungkin ya (1) , setidaknya jika Anda mampu memiliki baris baru (atau pipa itu ke tr -d '\n'...)
@ Kojiro: itu akan gagal jika Anda mencoba yesaliran \nkarakter. Alternatif yang menangani \nadalah: yes '' | tr '\n' "$c"- di mana $cbisa karakter apa saja dari berbagai karakter ASCII.
Peter.O
1
@ Peter.O Saya tidak yakin bagaimana Anda menafsirkan komentar saya berarti apa pun selain ekspresi yang harfiah dan statis yes 1 | tr -d $'\n'. Saya kira Anda bisa menggunakan shell yang tidak melakukan $''perawatan backslash, atau Anda bisa mencoba menemukan lokal yang berubah tr -d $'\n', tapi saya belum menemukannya.
kojiro
@kojiro: Anda yes 1 | tr -d $'\n'akan dengan senang hati mencetak aliran 1karakter dan hampir setiap nilai byte tunggal lainnya, tetapi tidak dapat mencetak aliran \nkarakter. OP ingin dapat menangani semua nilai byte "antara 0x01 dan 0xFF"
Peter.O
1
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
PSkocik
13
Nah, jika Anda benar - benar ingin mencapai ini, Anda dapat menggunakan pengait LD_PRELOAD . Ide dasarnya adalah menulis ulang fungsi dari pustaka C dan menggunakannya sebagai ganti fungsi yang normal.
Berikut adalah contoh sederhana di mana kita menimpa fungsi read () ke XOR buffer output dengan 0x42.
Implementasi naif akan XOR 0x42 pada setiap file yang kita baca, yang akan memiliki konsekuensi yang tidak diinginkan. Untuk mengatasi masalah ini, saya juga mengaitkan fungsi open () , membuatnya mengambil deskriptor file yang terkait dengan / dev / zero. Kemudian, kita hanya menjalankan XOR pada fungsi read () kita jika fd == dev_zero_fd.
Dengan penerapan Anda, Anda bisa memiliki tautan simbolis dari dari / dev / capbee ke / dev / zero, cari / dev / capbee dan tinggalkan / dev / zero saja. // dev / zero tidak akan sama dengan / dev / zero.
Robert Jacobs
1
@RobertJacobs Memang. Kami bahkan dapat membuat symlink / dev / 0x01, / dev / 0x02, / dev / 0x03, ... ke / dev / nol dan mengurai nama file untuk menentukan bitmask yang akan diterapkan.
yoann
11
Dalam hal kecepatan, yang tercepat saya temukan adalah:
$ PERLIO=:unix perl -e '$s="\1" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]
Di Debian saya, perlhasilkan 2,13GiB, sementara < /dev/zerohasilkan 8,73GiB. Hal apa yang dapat memengaruhi kinerja?
cuonglm
@cuonglm, ya, saya melihat beberapa variasi antara sistem, tetapi perlsecara konsisten lebih cepat daripada solusi lainnya. Saya mendapatkan hasil yang sama dengan program C yang dikompilasi yang setara. Tolok ukurnya ada pada aplikasi seperti pada penjadwal sistem di sini. Apa yang membuatnya paling berbeda adalah ukuran buffer yang sedang ditulis.
Stéphane Chazelas
@cuonglm Pipa memperlambatnya juga. Saya pikir cat /dev/zero| pv -a >/dev/nullakan memberi Anda sekitar 2 GiB per detik juga (itu pada sistem saya, sementara < /dev/zero) memberi saya sekitar 6GiBps.
PSkocik
@ StéphaneChazelas Boleh saya bertanya sistem apa yang Anda pakai, Stéphane Chazelas? Hasil pada saya sangat berbeda (saya bisa mendapatkan sekitar 2.1GiB dari versi perl). Saya menggunakan Linux ProBook 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/LinuxIntel i5 Core di dalamnya.
PSkocik
1
@PSkocik, Linux 3.16.0-4-amd64 # 1 SMP Debian 3.16.7-ckt9-3 (2015-04-23) x86_64 GNU / Linux, Intel (R) Core (TM) 2 Duo CPU T9600 @ 2.80GHz. Kernel yang lebih baru tampaknya membuat perbedaan (kecuali perl yang lebih baru: v5.20.2)
Stéphane Chazelas
7
Agak ada gunanya mencoba dan bitmask / xor nol byte, bukan? Mengambil byte dan xormemasukkannya dengan nol adalah larangan.
Cukup buat satu loop yang memberi Anda byte yang Anda inginkan dan letakkan di belakang pipa atau pipa bernama. Ini akan berperilaku sama seperti perangkat karakter (tidak akan membuang siklus CPU saat idle):
mkfifo pipe
while : ; do echo -n "a"; done > pipe &
Dan jika Anda ingin mengoptimalkannya secara super, Anda dapat menggunakan kode C di bawah ini:
Saya awalnya mencoba menggunakan putchar di C, tetapi lambat.
PSkocik
Karena penasaran, mengapa argc == 1+1bukannya agrc == 2?
Pasang kembali Monica - notmaynard
@iamnotmaynard Untuk mengingatkan diri sendiri bahwa ini 1 untuk baris perintah yang dapat dieksekusi ditambah 1 argumen. :-D
PSkocik
Ah. Itu dugaan saya, tetapi ingin memastikan tidak ada alasan rahasia.
Pasang kembali Monica - notmaynard
"Mengambil byte dan xoring dengan nol adalah no-op." Hal ini tidak benar: 0 XOR X == X.
jacwah
5
Baca nol, terjemahkan setiap nol ke pola Anda!
Kami membaca nol byte dari /dev/zero, dan gunakan truntuk menerapkan bit mask ke masing-masing byte dengan menerjemahkan setiap byte nol:
$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$
Oktal 176 adalah kode ascii ~, jadi kami mendapatkan 10 ~. (Di $akhir output menunjukkan di shell saya bahwa tidak ada garis akhir - itu bisa terlihat berbeda untuk Anda)
Jadi, mari kita buat 0xFFbyte: Hex 0xFFadalah oktal 0377. Nol terdepan ditinggalkan untuk trbaris perintah; Pada akhirnya, hexdumpdigunakan untuk membuat output dapat dibaca.
Anda perlu menggunakan kode oktal karakter di sini, bukan heksadesimal. Jadi kisaran dari \000oktal \377(sama seperti 0xFF).
Gunakan ascii -xdan ascii -ountuk mendapatkan tabel karakter dengan angka indeks heksadesimal atau oktal.
(Untuk tabel dengan desimal dan heksadesimal, adil ascii).
Cukup cepat
Ini berjalan cukup cepat, dibandingkan dengan hanya menggunakan nol: cat /dev/zerohanya empat kali lebih cepat, sementara itu dapat memanfaatkan buffering IO dengan sempurna, yang trtidak bisa.
$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]
$ </dev/zero cat | pv -a >/dev/null
[4.37GB/s]
Tergantung apa yang ingin Anda lakukan dengan data dan seberapa fleksibel Anda ingin menggunakannya.
Kasus terburuk jika Anda membutuhkan kecepatan, Anda dapat melakukan hal yang sama dengan / dev / zero, dan hanya mengkompilasi / dev / one, / dev / two, .. / dev / fourtytwo .. dan seterusnya perangkat.
Dalam kebanyakan kasus, lebih baik membuat data secara langsung di tempat yang diperlukan, jadi di dalam program / skrip sebagai konstanta. Dengan lebih banyak informasi, orang dapat lebih membantu Anda.
0x00
- masing ke nilai tertentu atau ke nilai acak dalam0x00-0xFF
rentang?444444...
bukan yang acakJawaban:
bash
Kode berikut ini diatur untuk bekerja dengan byte yang diwakili dalam biner . Namun Anda dapat dengan mudah mengubahnya untuk menangani ocatal , desimal atau hex dengan hanya mengubah radixr
nilai2
untuk8
,10
atau16
masing-masing dan pengaturanb=
yang sesuai.EDIT - Ini menangani berbagai nilai byte: hex 00 - FF (ketika saya menulis 00-7F di bawah ini, saya hanya mempertimbangkan karakter byte tunggal UTF-8).
Jika, misalnya, Anda hanya ingin 4 byte
(karakter dalam UTF-8 'ASCII'-only hex 00-7F range), Anda dapat menyalurkannya ke head :... | head -c4
Output (4 karakter):
Untuk melihat output dalam format 8-bit, masukkan ke dalam
xxd
(atau dump byte 1 dan 0 lainnya *):mis.
b=10000000
dan perpipaan ke:... | head -c4 | xxd -b
sumber
o=$(printf ...)
untuk baris kedua?-v
menyebabkan tthe keluaran untuk langsung mengatur variabel bernama segera setelah; dalam hal ini yang nama variabel adalaho
(untuk oktal ) - catatan bahwa-v
opsi berlaku untuk shell-builtin versiprintf
(bukan ke / usr / bin / printf versi)-v
opsi memastikan variabel diatur ke persis apa yang Anda tentukan.$(...)
mengubah output terlebih dahulu. Itulah sebabnya mengapao=$(printf '\n')
tidak akan memiliki efek yang Anda harapkan, sedangkan sebaliknyaprintf -vo '\n'
. (Tidak masalah di sini, karena output di sini adalah dalam bentuk yang tidak terpengaruh oleh transformasi seperti itu, tetapi jika Anda tidak mengetahui-v
opsi tersebut, maka ini mungkin berguna untuk diketahui.)Anda tidak dapat dengan mudah melakukan itu.
Anda mungkin mempertimbangkan untuk menulis modul kernel Anda sendiri yang menyediakan perangkat seperti itu. Saya tidak merekomendasikan itu.
Anda dapat menulis sebuah program C kecil yang menulis aliran tak terbatas dari byte yang sama pada beberapa pipa (atau pada
stdout
) atau FIFO.Anda dapat menggunakan tr (1) untuk membaca
/dev/zero
dan menerjemahkan setiap 0 byte ke sesuatu yang lain.Anda bisa menggunakan mungkin ya (1) , setidaknya jika Anda mampu memiliki baris baru (atau pipa itu ke
tr -d '\n'
...)sumber
yes 1 | tr -d $'\n'
dalam hal ini.yes
aliran\n
karakter. Alternatif yang menangani\n
adalah:yes '' | tr '\n' "$c"
- di mana$c
bisa karakter apa saja dari berbagai karakter ASCII.yes 1 | tr -d $'\n'
. Saya kira Anda bisa menggunakan shell yang tidak melakukan$''
perawatan backslash, atau Anda bisa mencoba menemukan lokal yang berubahtr -d $'\n'
, tapi saya belum menemukannya.yes 1 | tr -d $'\n'
akan dengan senang hati mencetak aliran1
karakter dan hampir setiap nilai byte tunggal lainnya, tetapi tidak dapat mencetak aliran\n
karakter. OP ingin dapat menangani semua nilai byte "antara 0x01 dan 0xFF"loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
Nah, jika Anda benar - benar ingin mencapai ini, Anda dapat menggunakan pengait LD_PRELOAD . Ide dasarnya adalah menulis ulang fungsi dari pustaka C dan menggunakannya sebagai ganti fungsi yang normal.
Berikut adalah contoh sederhana di mana kita menimpa fungsi read () ke XOR buffer output dengan 0x42.
Implementasi naif akan XOR 0x42 pada setiap file yang kita baca, yang akan memiliki konsekuensi yang tidak diinginkan. Untuk mengatasi masalah ini, saya juga mengaitkan fungsi open () , membuatnya mengambil deskriptor file yang terkait dengan / dev / zero. Kemudian, kita hanya menjalankan XOR pada fungsi read () kita jika
fd == dev_zero_fd
.Pemakaian:
sumber
Dalam hal kecepatan, yang tercepat saya temukan adalah:
Untuk perbandingan:
sumber
perl
hasilkan 2,13GiB, sementara< /dev/zero
hasilkan 8,73GiB. Hal apa yang dapat memengaruhi kinerja?perl
secara konsisten lebih cepat daripada solusi lainnya. Saya mendapatkan hasil yang sama dengan program C yang dikompilasi yang setara. Tolok ukurnya ada pada aplikasi seperti pada penjadwal sistem di sini. Apa yang membuatnya paling berbeda adalah ukuran buffer yang sedang ditulis.cat /dev/zero| pv -a >/dev/null
akan memberi Anda sekitar 2 GiB per detik juga (itu pada sistem saya, sementara< /dev/zero
) memberi saya sekitar 6GiBps.Linux ProBook 3.13.0-24-generic #47-Ubuntu SMP Fri May 2 23:30:00 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Intel i5 Core di dalamnya.Agak ada gunanya mencoba dan bitmask / xor nol byte, bukan? Mengambil byte dan
xor
memasukkannya dengan nol adalah larangan.Cukup buat satu loop yang memberi Anda byte yang Anda inginkan dan letakkan di belakang pipa atau pipa bernama. Ini akan berperilaku sama seperti perangkat karakter (tidak akan membuang siklus CPU saat idle):
Dan jika Anda ingin mengoptimalkannya secara super, Anda dapat menggunakan kode C di bawah ini:
kompilasi & jalankan
Uji kinerja:
2.1GB / s pada mesin saya (bahkan sedikit lebih cepat dari
cat /dev/zero | pv -a >/dev/null
)sumber
argc == 1+1
bukannyaagrc == 2
?0 XOR X == X
.Baca nol, terjemahkan setiap nol ke pola Anda!
Kami membaca nol byte dari
/dev/zero
, dan gunakantr
untuk menerapkan bit mask ke masing-masing byte dengan menerjemahkan setiap byte nol:Oktal 176 adalah kode ascii
~
, jadi kami mendapatkan 10~
. (Di$
akhir output menunjukkan di shell saya bahwa tidak ada garis akhir - itu bisa terlihat berbeda untuk Anda)Jadi, mari kita buat
0xFF
byte: Hex0xFF
adalah oktal0377
. Nol terdepan ditinggalkan untuktr
baris perintah; Pada akhirnya,hexdump
digunakan untuk membuat output dapat dibaca.Anda perlu menggunakan kode oktal karakter di sini, bukan heksadesimal. Jadi kisaran dari
\000
oktal\377
(sama seperti0xFF
).Gunakan
ascii -x
danascii -o
untuk mendapatkan tabel karakter dengan angka indeks heksadesimal atau oktal.(Untuk tabel dengan desimal dan heksadesimal, adil
ascii
).Cukup cepat
Ini berjalan cukup cepat, dibandingkan dengan hanya menggunakan nol:
cat /dev/zero
hanya empat kali lebih cepat, sementara itu dapat memanfaatkan buffering IO dengan sempurna, yangtr
tidak bisa.sumber
Tergantung apa yang ingin Anda lakukan dengan data dan seberapa fleksibel Anda ingin menggunakannya.
Kasus terburuk jika Anda membutuhkan kecepatan, Anda dapat melakukan hal yang sama dengan / dev / zero, dan hanya mengkompilasi / dev / one, / dev / two, .. / dev / fourtytwo .. dan seterusnya perangkat.
Dalam kebanyakan kasus, lebih baik membuat data secara langsung di tempat yang diperlukan, jadi di dalam program / skrip sebagai konstanta. Dengan lebih banyak informasi, orang dapat lebih membantu Anda.
sumber
Infinte printf loop
Ganti
\u00
dengan byte yang Anda inginkan.while true ; do printf "\u00" ; done | yourapp
Kode C ++:
Kompilasi: ganti
Byte
dengan nilai yang Anda inginkan.g++ -O3 -o bin file.cpp -D Byte=0x01
Menggunakan
./bin | yourapp
sumber