Wie kann ich eine Bitmaske auf / dev / zero setzen, damit ich andere Bytes als Null erhalten kann?
20
Wie kann ich eine Bitmaske /dev/zeroaufsetzen, damit ich eine Quelle nicht nur für 0x00, sondern auch für ein beliebiges Byte zwischen 0x01 und 0xFF haben kann?
Ich gab eine Antwort auf diese Frage, aber als ich sie noch einmal las, glaubte ich, dass ich sie missverstanden hatte. Möchten Sie jeden 0x00in einen bestimmten Wert oder in einen zufälligen Wert im 0x00-0xFFBereich übersetzen?
Kos
1
@kos jeweils auf einen bestimmten Wert wie 444444...kein Zufallswert
Eduard Florinescu
Antworten:
18
Der folgende bashCode ist so eingestellt, dass er mit dem Byte arbeitet, das in der Binärdatei wiedergegeben wird . Allerdings können Sie es leicht zu handhaben ändern ocatal , dezimal oder hex einfach durch den Wechsel radixr Wert 2 zu 8, 10oder 16jeweils und Einstellung b=entsprechend.
BEARBEITEN - Es wird der gesamte Bereich der Bytewerte verarbeitet: hex 00 - FF (als ich 00-7F unten schrieb, habe ich nur Einzelbyte-UTF-8-Zeichen in Betracht gezogen).
Wenn Sie zum Beispiel nur 4 Bytes (Zeichen im UTF-8-Bereich 'ASCII'-only hex 00-7F) möchten , können Sie dies in head umleiten :... | head -c4
Ausgabe (4 Zeichen):
~~~~
Um die Ausgabe im 8-Bit-Format anzuzeigen, leiten Sie sie weiter in xxd(oder einen anderen Byte-Dump * von 1 und 0 ):
z. b=10000000und Rohrleitungen zu:... | head -c4 | xxd -b
Wollten Sie o=$(printf ...)für die zweite Zeile schreiben ?
Jwodder
1
@jwodder: Nein, die zweite Zeile ist wie gezeigt korrekt. Die Option printf-v bewirkt, dass die Ausgabe die unmittelbar nach ihr benannte Variable direkt setzt. In diesem Fall lautet der Variablenname o(für Oktal ). Beachten Sie, dass die -vOption für die Shell- Version von printf(nicht für die Version / usr / bin / printf ) gilt.
Peter.O
2
@jwodder Im Allgemeinen stellt die -vOption auch sicher, dass die Variable genau auf das eingestellt wird, was Sie angegeben haben. $(...)transformiert zuerst die Ausgabe. Das ist der Grund, warum o=$(printf '\n')nicht die erwartete Wirkung erzielt wird, wohingegen dies der printf -vo '\n'Fall ist. (Es spielt hier keine Rolle, da die Ausgabe hier in einer Form vorliegt, die von einer solchen Umwandlung nicht betroffen ist. Wenn Sie die -vOption jedoch nicht kennen, ist dies möglicherweise hilfreich.)
hvd
18
Das kann man nicht so einfach machen.
Sie können ein eigenes Kernelmodul schreiben, das ein solches Gerät bereitstellt. Das empfehle ich nicht.
Sie könnten ein winziges C-Programm schreiben, das einen unendlichen Strom gleicher Bytes auf eine Pipe (oder auf stdout) oder ein FIFO schreibt .
Sie könnten tr (1) verwenden , um aus /dev/zerojedem 0-Byte etwas anderes zu lesen und es zu übersetzen.
Sie könnten vielleicht yes (1) verwenden , zumindest wenn Sie es sich leisten können, Zeilenumbrüche zu haben (oder es weiterzuleiten tr -d '\n'...)
Oder verwenden Sie yes 1 | tr -d $'\n'für diese Angelegenheit.
Kojiro
3
@kojiro: Das wird scheitern, wenn Sie versuchen, yeseinen Strom von \nZeichen. Eine Alternative, die behandelt wird, \nist: yes '' | tr '\n' "$c"- Wo $ckann ein beliebiges Zeichen des gesamten ASCII-Zeichenbereichs sein.
Peter.O
1
@ Peter.O Ich bin mir nicht sicher, wie Sie meinen Kommentar interpretiert haben, um etwas anderes als den wörtlichen, statischen Ausdruck zu bedeuten yes 1 | tr -d $'\n'. Ich nehme an, Sie könnten eine Shell verwenden, die die $''Backslash-Behandlung nicht ausführt, oder Sie könnten versuchen, ein Gebietsschema zu finden, das sich ändert tr -d $'\n', aber ich habe es noch nicht gefunden.
Kojiro
@kojiro: Sie yes 1 | tr -d $'\n'werden ganz gerne einen 1Zeichenstrom und fast jeden anderen Einzelbyte -Wert drucken, aber es kann keinen \nZeichenstrom drucken . Das OP möchte alle Bytewerte "zwischen 0x01 und 0xFF" verarbeiten können
Peter.O
1
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
PSkocik
13
Wenn Sie dies im wahrsten Sinne des Wortes erreichen möchten, können Sie einen LD_PRELOAD-Hook verwenden . Die Grundidee ist, eine Funktion aus der C-Bibliothek neu zu schreiben und anstelle der normalen zu verwenden.
Hier ist ein einfaches Beispiel, in dem wir die Funktion read () überschreiben, um den Ausgabepuffer mit 0x42 zu XOR zu verknüpfen.
Eine naive Implementierung würde XOR 0x42 für jede gelesene Datei bedeuten, was unerwünschte Konsequenzen hätte. Um dieses Problem zu lösen, habe ich auch die open () - Funktion eingebunden, sodass sie den Dateideskriptor abruft, der mit / dev / zero verknüpft ist. Dann führen wir das XOR in unserer read () - Funktion nur aus, wenn fd == dev_zero_fd.
In Anbetracht Ihrer Implementierung könnten Sie eine symbolische Verknüpfung von / dev / capbee zu / dev / zero haben, nach / dev / capbee suchen und / dev / zero in Ruhe lassen. // dev / zero ist nicht dasselbe wie / dev / zero.
Robert Jacobs
1
@ RobertJacobs In der Tat. Wir könnten sogar symlinks / dev / 0x01, / dev / 0x02, / dev / 0x03, ... nach / dev / zero generieren und den Dateinamen analysieren, um die anzuwendende Bitmaske zu bestimmen.
Yoann
11
In Bezug auf die Geschwindigkeit war die schnellste, die ich gefunden habe:
$ PERLIO=:unix perl -e '$s="\1" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]
In meinem Debian perlergeben sich 2,13GiB, während sich < /dev/zero8,73GiB ergeben. Was kann die Leistung beeinträchtigen?
Cuonglm
@ Cuonglm, ja, ich sehe einige Unterschiede zwischen den Systemen, aber perlist durchweg schneller als die anderen Lösungen. Ich bekomme den gleichen Durchsatz wie mit dem gleichwertigen kompilierten C-Programm. Der Benchmark bezieht sich sowohl auf die Anwendung als auch auf den Scheduler des Systems. Was den Unterschied am meisten ausmacht, ist die Größe der Puffer, die geschrieben werden.
Stéphane Chazelas
@cuonglm Das Rohr verlangsamt es auch. Ich denke cat /dev/zero| pv -a >/dev/null, dass Sie ungefähr 2 GiBs pro Sekunde auch geben werden (es tut auf meinem System, während < /dev/zero), gibt mir um 6GiBps.
PSkocik
@ StéphaneChazelas Darf ich fragen, auf welchem System bist du, Stéphane Chazelas? Die Ergebnisse auf meinem unterscheiden sich ziemlich (ich kann ungefähr 2.1GiB aus der Perl-Version herausbekommen). Ich bin auf 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 drin.
PSkocik
1
@PSkocik, Linux 3.16.0-4-amd64 # 1 SMP Debian 3.16.7-ckt9-3 (23.04.2015) x86_64 GNU / Linux, Intel (R) Core (TM) 2 Duo-CPU T9600 bei 2,80 GHz. Der neuere Kernel scheint einen Unterschied zu machen (es sei denn, es ist der neuere Perl: v5.20.2)
Stéphane Chazelas
7
Es ist irgendwie sinnlos zu versuchen, eine Bitmaske / x oder null Bytes zu erstellen, nicht wahr? Ein Byte zu nehmen und xormit Null zu belegen, ist ein No-Op.
Erstellen Sie einfach eine Schleife, die die gewünschten Bytes enthält, und setzen Sie sie hinter eine Pipe oder Named Pipe. Es verhält sich so ziemlich wie ein Zeichengerät (verschwendet im Leerlauf keine CPU-Zyklen):
mkfifo pipe
while : ; do echo -n "a"; done > pipe &
Und wenn Sie es optimieren möchten, können Sie den folgenden C-Code verwenden:
Ich habe ursprünglich versucht, Putchar in C zu verwenden, aber es war langsam.
PSkocik
Warum aus Neugier argc == 1+1statt agrc == 2?
Setzen Sie Monica iamnotmaynard am
@iamnotmaynard Um mich daran zu erinnern, dass es 1 für die ausführbare Befehlszeile plus 1 Argument ist. :-D
PSkocik
Ah. Das war meine Vermutung, aber ich wollte sicherstellen, dass es keinen geheimen Grund gab.
Setzen Sie Monica iamnotmaynard am
"Ein Byte zu nehmen und es mit Null zu xoren, ist ein No-Op." Das ist nicht wahr: 0 XOR X == X.
Jacwah
5
Lesen Sie Nullen, übersetzen Sie jede Null in Ihr Muster!
Wir lesen Null-Bytes aus /dev/zeround trwenden eine Bitmaske auf jedes der Bytes an, indem wir jedes Null-Byte übersetzen:
$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$
Oktal 176 ist der ASCII-Code von ~, also erhalten wir 10 ~. (Das $am Ende der Ausgabe zeigt in meiner Shell an, dass es kein Zeilenende gab - es könnte für Sie anders aussehen)
Lassen Sie uns also 0xFFBytes erstellen : Hex 0xFFist oktal 0377. Die führende Null wird in der trBefehlszeile weggelassen. Am Ende hexdumpwird verwendet, um die Ausgabe lesbar zu machen.
Sie müssen hier die Oktalcodes der Zeichen anstelle des Hexadezimals verwenden. Es ist also der Bereich von \000bis oktal \377(genauso wie 0xFF).
Verwenden Sie ascii -xund ascii -o, um eine Tabelle der Zeichen mit hexadezimalen oder oktalen Indexnummern zu erhalten.
(Für eine Tabelle mit Dezimal- und Hexadezimalzahl nur ascii).
Ziemlich schnell
Es läuft ziemlich schnell, verglichen mit der Verwendung von Nullen: Es cat /dev/zeroist nur viermal so schnell, während es die E / A-Pufferung perfekt nutzen trkann , was nicht möglich ist.
$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]
$ </dev/zero cat | pv -a >/dev/null
[4.37GB/s]
Hängt davon ab, was Sie mit den Daten machen möchten und wie flexibel Sie sie verwenden möchten.
Im schlimmsten Fall, wenn Sie Geschwindigkeit benötigen, können Sie das Gleiche wie mit / dev / zero tun und einfach die Geräte / dev / one, / dev / two, ... / dev / fourtytwo ... und so weiter kompilieren.
In den meisten Fällen ist es besser, die Daten direkt dort zu erstellen, wo sie benötigt werden, also innerhalb eines Programms / Skripts als Konstante. Mit mehr Informationen könnten Ihnen die Leute besser helfen.
0x00
in einen bestimmten Wert oder in einen zufälligen Wert im0x00-0xFF
Bereich übersetzen?444444...
kein ZufallswertAntworten:
Der folgende
bash
Code ist so eingestellt, dass er mit dem Byte arbeitet, das in der Binärdatei wiedergegeben wird . Allerdings können Sie es leicht zu handhaben ändern ocatal , dezimal oder hex einfach durch den Wechsel radixr
Wert2
zu8
,10
oder16
jeweils und Einstellungb=
entsprechend.BEARBEITEN - Es wird der gesamte Bereich der Bytewerte verarbeitet: hex 00 - FF (als ich 00-7F unten schrieb, habe ich nur Einzelbyte-UTF-8-Zeichen in Betracht gezogen).
Wenn Sie zum Beispiel nur 4 Bytes
(Zeichen im UTF-8-Bereich 'ASCII'-only hex 00-7F) möchten, können Sie dies in headumleiten:... | head -c4
Ausgabe (4 Zeichen):
Um die Ausgabe im 8-Bit-Format anzuzeigen, leiten Sie sie weiter in
xxd
(oder einen anderen Byte-Dump * von 1 und 0 ):z.
b=10000000
und Rohrleitungen zu:... | head -c4 | xxd -b
quelle
o=$(printf ...)
für die zweite Zeile schreiben ?-v
bewirkt, dass die Ausgabe die unmittelbar nach ihr benannte Variable direkt setzt. In diesem Fall lautet der Variablennameo
(für Oktal ). Beachten Sie, dass die-v
Option für die Shell- Version vonprintf
(nicht für die Version / usr / bin / printf ) gilt.-v
Option auch sicher, dass die Variable genau auf das eingestellt wird, was Sie angegeben haben.$(...)
transformiert zuerst die Ausgabe. Das ist der Grund, warumo=$(printf '\n')
nicht die erwartete Wirkung erzielt wird, wohingegen dies derprintf -vo '\n'
Fall ist. (Es spielt hier keine Rolle, da die Ausgabe hier in einer Form vorliegt, die von einer solchen Umwandlung nicht betroffen ist. Wenn Sie die-v
Option jedoch nicht kennen, ist dies möglicherweise hilfreich.)Das kann man nicht so einfach machen.
Sie können ein eigenes Kernelmodul schreiben, das ein solches Gerät bereitstellt. Das empfehle ich nicht.
Sie könnten ein winziges C-Programm schreiben, das einen unendlichen Strom gleicher Bytes auf eine Pipe (oder auf
stdout
) oder ein FIFO schreibt .Sie könnten tr (1) verwenden , um aus
/dev/zero
jedem 0-Byte etwas anderes zu lesen und es zu übersetzen.Sie könnten vielleicht yes (1) verwenden , zumindest wenn Sie es sich leisten können, Zeilenumbrüche zu haben (oder es weiterzuleiten
tr -d '\n'
...)quelle
yes 1 | tr -d $'\n'
für diese Angelegenheit.yes
einen Strom von\n
Zeichen. Eine Alternative, die behandelt wird,\n
ist:yes '' | tr '\n' "$c"
- Wo$c
kann ein beliebiges Zeichen des gesamten ASCII-Zeichenbereichs sein.yes 1 | tr -d $'\n'
. Ich nehme an, Sie könnten eine Shell verwenden, die die$''
Backslash-Behandlung nicht ausführt, oder Sie könnten versuchen, ein Gebietsschema zu finden, das sich änderttr -d $'\n'
, aber ich habe es noch nicht gefunden.yes 1 | tr -d $'\n'
werden ganz gerne einen1
Zeichenstrom und fast jeden anderen Einzelbyte -Wert drucken, aber es kann keinen\n
Zeichenstrom drucken . Das OP möchte alle Bytewerte "zwischen 0x01 und 0xFF" verarbeiten könnenloop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
Wenn Sie dies im wahrsten Sinne des Wortes erreichen möchten, können Sie einen LD_PRELOAD-Hook verwenden . Die Grundidee ist, eine Funktion aus der C-Bibliothek neu zu schreiben und anstelle der normalen zu verwenden.
Hier ist ein einfaches Beispiel, in dem wir die Funktion read () überschreiben, um den Ausgabepuffer mit 0x42 zu XOR zu verknüpfen.
Eine naive Implementierung würde XOR 0x42 für jede gelesene Datei bedeuten, was unerwünschte Konsequenzen hätte. Um dieses Problem zu lösen, habe ich auch die open () - Funktion eingebunden, sodass sie den Dateideskriptor abruft, der mit / dev / zero verknüpft ist. Dann führen wir das XOR in unserer read () - Funktion nur aus, wenn
fd == dev_zero_fd
.Verwendung:
quelle
In Bezug auf die Geschwindigkeit war die schnellste, die ich gefunden habe:
Zum Vergleich:
quelle
perl
ergeben sich 2,13GiB, während sich< /dev/zero
8,73GiB ergeben. Was kann die Leistung beeinträchtigen?perl
ist durchweg schneller als die anderen Lösungen. Ich bekomme den gleichen Durchsatz wie mit dem gleichwertigen kompilierten C-Programm. Der Benchmark bezieht sich sowohl auf die Anwendung als auch auf den Scheduler des Systems. Was den Unterschied am meisten ausmacht, ist die Größe der Puffer, die geschrieben werden.cat /dev/zero| pv -a >/dev/null
, dass Sie ungefähr 2 GiBs pro Sekunde auch geben werden (es tut auf meinem System, während< /dev/zero
), gibt mir um 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 drin.Es ist irgendwie sinnlos zu versuchen, eine Bitmaske / x oder null Bytes zu erstellen, nicht wahr? Ein Byte zu nehmen und
xor
mit Null zu belegen, ist ein No-Op.Erstellen Sie einfach eine Schleife, die die gewünschten Bytes enthält, und setzen Sie sie hinter eine Pipe oder Named Pipe. Es verhält sich so ziemlich wie ein Zeichengerät (verschwendet im Leerlauf keine CPU-Zyklen):
Und wenn Sie es optimieren möchten, können Sie den folgenden C-Code verwenden:
kompilieren & ausführen
Leistungstest:
2,1 GB / s auf meinem Computer (sogar etwas schneller als
cat /dev/zero | pv -a >/dev/null
)quelle
argc == 1+1
stattagrc == 2
?0 XOR X == X
.Lesen Sie Nullen, übersetzen Sie jede Null in Ihr Muster!
Wir lesen Null-Bytes aus
/dev/zero
undtr
wenden eine Bitmaske auf jedes der Bytes an, indem wir jedes Null-Byte übersetzen:Oktal 176 ist der ASCII-Code von
~
, also erhalten wir 10~
. (Das$
am Ende der Ausgabe zeigt in meiner Shell an, dass es kein Zeilenende gab - es könnte für Sie anders aussehen)Lassen Sie uns also
0xFF
Bytes erstellen : Hex0xFF
ist oktal0377
. Die führende Null wird in dertr
Befehlszeile weggelassen. Am Endehexdump
wird verwendet, um die Ausgabe lesbar zu machen.Sie müssen hier die Oktalcodes der Zeichen anstelle des Hexadezimals verwenden. Es ist also der Bereich von
\000
bis oktal\377
(genauso wie0xFF
).Verwenden Sie
ascii -x
undascii -o
, um eine Tabelle der Zeichen mit hexadezimalen oder oktalen Indexnummern zu erhalten.(Für eine Tabelle mit Dezimal- und Hexadezimalzahl nur
ascii
).Ziemlich schnell
Es läuft ziemlich schnell, verglichen mit der Verwendung von Nullen: Es
cat /dev/zero
ist nur viermal so schnell, während es die E / A-Pufferung perfekt nutzentr
kann , was nicht möglich ist.quelle
Hängt davon ab, was Sie mit den Daten machen möchten und wie flexibel Sie sie verwenden möchten.
Im schlimmsten Fall, wenn Sie Geschwindigkeit benötigen, können Sie das Gleiche wie mit / dev / zero tun und einfach die Geräte / dev / one, / dev / two, ... / dev / fourtytwo ... und so weiter kompilieren.
In den meisten Fällen ist es besser, die Daten direkt dort zu erstellen, wo sie benötigt werden, also innerhalb eines Programms / Skripts als Konstante. Mit mehr Informationen könnten Ihnen die Leute besser helfen.
quelle
Endlosschleife
Ersetzen Sie
\u00
mit dem gewünschten Byte.while true ; do printf "\u00" ; done | yourapp
C ++ Code:
Kompilieren: Ersetzen Sie
Byte
mit dem gewünschten Wert.g++ -O3 -o bin file.cpp -D Byte=0x01
Verwenden
./bin | yourapp
quelle