Comment puis-je mettre un masque de bits sur / dev / zero pour pouvoir obtenir des octets autres que zéro?
20
Comment puis-je mettre un masque de bits /dev/zeropour que je puisse avoir une source non seulement pour 0x00 mais aussi pour tout octet entre 0x01 et 0xFF?
J'ai répondu à cette question, mais en la relisant, je pense que je l'ai mal comprise. Voulez-vous traduire chacun 0x00en une valeur spécifique ou en une valeur aléatoire dans la 0x00-0xFFplage?
kos
1
@kos chacun à une valeur spécifique comme 444444...pas aléatoire
Eduard Florinescu
Réponses:
18
Le bashcode suivant est configuré pour fonctionner avec l'octet étant representré en binaire . Cependant, vous pouvez facilement le modifier pour gérer ocatal , décimal ou hexadécimal en changeant simplement la valeur radixr de 2 en 8, 10ou 16respectivement et en définissant en b=conséquence.
EDIT - Il gère la plage complète des valeurs d'octets: hex 00 - FF (lorsque j'ai écrit 00-7F ci-dessous, je ne considérais que les caractères UTF-8 à un octet).
Si, par exemple, vous ne voulez que 4 octets (caractères dans la plage hex 00-7F uniquement ASCII 'UTF-8) , vous pouvez le diriger dans head :... | head -c4
Sortie (4 caractères):
~~~~
Pour voir la sortie au format 8 bits, dirigez-la vers xxd(ou tout autre vidage d'octets 1 et 0 *):
par exemple. b=10000000et tuyauterie pour:... | head -c4 | xxd -b
Vouliez-vous écrire o=$(printf ...)pour la deuxième ligne?
jwodder
1
@jwodder: Non, la deuxième ligne est correcte comme indiqué. L' option printf-v fait que la sortie définit directement la variable nommée immédiatement après elle; dans ce cas, le nom de cette variable est o(pour octal ) - notez que l' -voption s'applique à la version intégrée au shell de printf(pas à la version / usr / bin / printf )
Peter.O
2
@jwodder De plus, en général, l' -voption s'assure que la variable est définie exactement sur ce que vous avez spécifié. $(...)transforme la sortie en premier. C'est pourquoi o=$(printf '\n')n'aura pas l'effet que vous attendez, alors que le printf -vo '\n'fait. (Cela n'a pas d'importance ici, car la sortie ici est sous une forme qui n'est pas affectée par une telle transformation, mais si vous n'étiez pas au courant de l' -voption, cela pourrait être utile de le savoir.)
hvd
18
Vous ne pouvez pas facilement faire cela.
Vous pourriez envisager d'écrire votre propre module de noyau fournissant un tel périphérique. Je ne le recommande pas.
Vous pouvez écrire un petit programme C en écrivant un flux infini de mêmes octets sur un tube (ou sur stdout) ou FIFO.
Vous pouvez utiliser tr (1) pour lire /dev/zeroet traduire tous les 0 octets en autre chose.
Vous pourriez peut-être utiliser oui (1) , du moins si vous pouvez vous permettre d'avoir des retours à la ligne (ou bien les canaliser tr -d '\n'...)
@kojiro: cela échouera si vous essayez yesun flux de \ncaractères. Une alternative qui gère \nest: yes '' | tr '\n' "$c"- où $cpeut être n'importe quel caractère de la gamme complète de caractères ASCII.
Peter.O
1
@ Peter.O Je ne sais pas comment vous avez interprété mon commentaire comme autre chose que l'expression statique et littérale yes 1 | tr -d $'\n'. Je suppose que vous pouvez utiliser un shell qui ne fait pas le $''traitement de barre oblique inverse, ou vous pouvez essayer de trouver un paramètre régional qui change tr -d $'\n', mais je ne l'ai pas encore trouvé.
kojiro
@kojiro: Vous yes 1 | tr -d $'\n'imprimerez très volontiers un flux de 1caractères et presque toutes les autres valeurs à un octet, mais il ne peut pas imprimer un flux de \ncaractères. L'OP veut être capable de gérer toutes les valeurs d'octets "entre 0x01 et 0xFF"
Peter.O
1
loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
PSkocik
13
Eh bien, si vous voulez littéralement y parvenir, vous pouvez utiliser un hook LD_PRELOAD . L'idée de base est de réécrire une fonction de la bibliothèque C et de l'utiliser à la place de la normale.
Voici un exemple simple où nous remplaçons la fonction read () pour XOR le tampon de sortie avec 0x42.
Une implémentation naïve ferait XOR 0x42 sur chaque fichier lu, ce qui aurait des conséquences indésirables. Afin de résoudre ce problème, j'ai également accroché la fonction open () , ce qui lui permet de récupérer le descripteur de fichier associé à / dev / zero. Ensuite, nous n'effectuons le XOR dans notre fonction read () que si fd == dev_zero_fd.
Compte tenu de votre implémentation, vous pouvez avoir un lien symbolique de / dev / capbee vers / dev / zero, rechercher / dev / capbee et laisser / dev / zero seul. // dev / zero ne sera pas identique à / dev / zero.
Robert Jacobs
1
@RobertJacobs En effet. Nous pourrions même générer des liens symboliques / dev / 0x01, / dev / 0x02, / dev / 0x03, ... vers / dev / zero et analyser le nom de fichier pour déterminer le masque de bits à appliquer.
yoann
11
En termes de vitesse, la plus rapide que j'ai trouvée était:
$ PERLIO=:unix perl -e '$s="\1" x 65536; for(;;){print $s}' | pv -a > /dev/null
[4.02GiB/s]
Dans mon Debian, perldonnez 2,13 Go, tandis que vous < /dev/zeroobtenez 8,73 Go. Quelle chose peut affecter les performances?
cuonglm
@cuonglm, oui, je vois une certaine variation entre les systèmes, mais perlest toujours plus rapide que les autres solutions. J'obtiens le même débit qu'avec le programme C compilé équivalent. Le benchmark est autant sur l'application que sur l'ordonnanceur du système ici. Ce qui fait la différence, c'est la taille des tampons en cours d'écriture.
Stéphane Chazelas
@cuonglm Le tuyau le ralentit aussi. Je pense que cat /dev/zero| pv -a >/dev/nullcela vous donnera également environ 2 Gio par seconde (il le fait sur mon système, alors < /dev/zero) me donne environ 6 Gbits / s.
PSkocik
@ StéphaneChazelas Puis-je vous demander sur quel système êtes-vous, Stéphane Chazelas? Les résultats sur le mien sont assez différents (je peux obtenir environ 2,1 Go de la version Perl). Je suis sur 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 à l'intérieur.
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. Le nouveau noyau semble faire la différence (à moins qu'il ne s'agisse du dernier perl: v5.20.2)
Stéphane Chazelas
7
C'est un peu inutile d'essayer de bitmask / xor zéro octets, n'est-ce pas? Prendre un octet et le xormettre à zéro est un no-op.
Créez simplement une boucle qui vous donne les octets que vous voulez et placez-la derrière un tuyau ou un tuyau nommé. Il se comportera à peu près de la même manière qu'un périphérique de caractères (ne gaspillera pas les cycles de processeur lorsqu'il est inactif):
mkfifo pipe
while : ; do echo -n "a"; done > pipe &
Et si vous voulez le super-optimiser, vous pouvez utiliser le code C ci-dessous:
J'ai essayé à l'origine d'utiliser putchar en C, mais c'était lent.
PSkocik
Par curiosité, pourquoi argc == 1+1au lieu de agrc == 2?
Reinstate Monica - notmaynard
@iamnotmaynard Pour me rappeler que c'est 1 pour l'exécutable de ligne de commande plus 1 argument. :-D
PSkocik
Ah. C'était ma supposition, mais je voulais m'assurer qu'il n'y avait pas de raison secrète.
Reinstate Monica - notmaynard
"Prendre un octet et le xorer avec zéro est un no-op." Ce n'est pas vrai: 0 XOR X == X.
jacwah
5
Lisez les zéros, traduisez chaque zéro à votre modèle!
Nous lisons zéro octet /dev/zeroet utilisons trpour appliquer un masque de bits à chacun des octets en traduisant chaque octet zéro:
$ </dev/zero tr '\000' '\176' | head -c 10
~~~~~~~~~~$
Octal 176 est le code ascii de ~, donc nous obtenons 10 ~. (Le $à la fin de la sortie indique dans mon shell qu'il n'y avait pas de fin de ligne - cela pourrait être différent pour vous)
Créons donc des 0xFFoctets: Hex 0xFFest octal 0377. Le zéro de tête est omis pour la trligne de commande; À la fin, hexdumpest utilisé pour rendre la sortie lisible.
Vous devez utiliser les codes octaux des caractères ici, au lieu de l'hexadécimal. C'est donc la plage de \000à octal \377(identique à 0xFF).
Utilisez ascii -xet ascii -opour obtenir un tableau des caractères avec des numéros d'index hexadécimaux ou octaux.
(Pour un tableau avec décimal et hexadécimal, juste ascii).
Tres rapide
Il fonctionne assez rapidement, comparé à la simple utilisation des zéros: il cat /dev/zeron'est que quatre fois plus rapide, alors qu'il peut faire un usage parfait de la mise en mémoire tampon d'E / S, ce qui trn'est pas possible.
$ </dev/zero tr '\000' '\176' | pv -a >/dev/null
[ 913MB/s]
$ </dev/zero cat | pv -a >/dev/null
[4.37GB/s]
Cela dépend de ce que vous voulez faire avec les données et de la flexibilité avec laquelle vous souhaitez les utiliser.
Dans le pire des cas, si vous avez besoin de vitesse, vous pouvez faire la même chose que / dev / zero, et simplement compiler les périphériques / dev / one, / dev / two, .. / dev / fourtytwo .. et ainsi de suite.
Dans la plupart des cas, il devrait être préférable de créer les données directement là où elles sont nécessaires, donc à l'intérieur d'un programme / script en tant que constante. Avec plus d'informations, les gens pourraient mieux vous aider.
0x00
en une valeur spécifique ou en une valeur aléatoire dans la0x00-0xFF
plage?444444...
pas aléatoireRéponses:
Le
bash
code suivant est configuré pour fonctionner avec l'octet étant representré en binaire . Cependant, vous pouvez facilement le modifier pour gérer ocatal , décimal ou hexadécimal en changeant simplement la valeur radixr
de2
en8
,10
ou16
respectivement et en définissant enb=
conséquence.EDIT - Il gère la plage complète des valeurs d'octets: hex 00 - FF (lorsque j'ai écrit 00-7F ci-dessous, je ne considérais que les caractères UTF-8 à un octet).
Si, par exemple, vous ne voulez que 4 octets
(caractères dans la plage hex 00-7F uniquement ASCII 'UTF-8), vous pouvez le diriger dans head :... | head -c4
Sortie (4 caractères):
Pour voir la sortie au format 8 bits, dirigez-la vers
xxd
(ou tout autre vidage d'octets 1 et 0 *):par exemple.
b=10000000
et tuyauterie pour:... | head -c4 | xxd -b
la source
o=$(printf ...)
pour la deuxième ligne?-v
fait que la sortie définit directement la variable nommée immédiatement après elle; dans ce cas, le nom de cette variable esto
(pour octal ) - notez que l'-v
option s'applique à la version intégrée au shell deprintf
(pas à la version / usr / bin / printf )-v
option s'assure que la variable est définie exactement sur ce que vous avez spécifié.$(...)
transforme la sortie en premier. C'est pourquoio=$(printf '\n')
n'aura pas l'effet que vous attendez, alors que leprintf -vo '\n'
fait. (Cela n'a pas d'importance ici, car la sortie ici est sous une forme qui n'est pas affectée par une telle transformation, mais si vous n'étiez pas au courant de l'-v
option, cela pourrait être utile de le savoir.)Vous ne pouvez pas facilement faire cela.
Vous pourriez envisager d'écrire votre propre module de noyau fournissant un tel périphérique. Je ne le recommande pas.
Vous pouvez écrire un petit programme C en écrivant un flux infini de mêmes octets sur un tube (ou sur
stdout
) ou FIFO.Vous pouvez utiliser tr (1) pour lire
/dev/zero
et traduire tous les 0 octets en autre chose.Vous pourriez peut-être utiliser oui (1) , du moins si vous pouvez vous permettre d'avoir des retours à la ligne (ou bien les canaliser
tr -d '\n'
...)la source
yes 1 | tr -d $'\n'
d'ailleurs.yes
un flux de\n
caractères. Une alternative qui gère\n
est:yes '' | tr '\n' "$c"
- où$c
peut être n'importe quel caractère de la gamme complète de caractères ASCII.yes 1 | tr -d $'\n'
. Je suppose que vous pouvez utiliser un shell qui ne fait pas le$''
traitement de barre oblique inverse, ou vous pouvez essayer de trouver un paramètre régional qui changetr -d $'\n'
, mais je ne l'ai pas encore trouvé.yes 1 | tr -d $'\n'
imprimerez très volontiers un flux de1
caractères et presque toutes les autres valeurs à un octet, mais il ne peut pas imprimer un flux de\n
caractères. L'OP veut être capable de gérer toutes les valeurs d'octets "entre 0x01 et 0xFF"loop() { if [ "$1" = $'\n' ]; then yes "$1"; else yes "$1" | tr -d $'\n' ; fi;
Eh bien, si vous voulez littéralement y parvenir, vous pouvez utiliser un hook LD_PRELOAD . L'idée de base est de réécrire une fonction de la bibliothèque C et de l'utiliser à la place de la normale.
Voici un exemple simple où nous remplaçons la fonction read () pour XOR le tampon de sortie avec 0x42.
Une implémentation naïve ferait XOR 0x42 sur chaque fichier lu, ce qui aurait des conséquences indésirables. Afin de résoudre ce problème, j'ai également accroché la fonction open () , ce qui lui permet de récupérer le descripteur de fichier associé à / dev / zero. Ensuite, nous n'effectuons le XOR dans notre fonction read () que si
fd == dev_zero_fd
.Usage:
la source
En termes de vitesse, la plus rapide que j'ai trouvée était:
En comparaison:
la source
perl
donnez 2,13 Go, tandis que vous< /dev/zero
obtenez 8,73 Go. Quelle chose peut affecter les performances?perl
est toujours plus rapide que les autres solutions. J'obtiens le même débit qu'avec le programme C compilé équivalent. Le benchmark est autant sur l'application que sur l'ordonnanceur du système ici. Ce qui fait la différence, c'est la taille des tampons en cours d'écriture.cat /dev/zero| pv -a >/dev/null
cela vous donnera également environ 2 Gio par seconde (il le fait sur mon système, alors< /dev/zero
) me donne environ 6 Gbits / s.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 à l'intérieur.C'est un peu inutile d'essayer de bitmask / xor zéro octets, n'est-ce pas? Prendre un octet et le
xor
mettre à zéro est un no-op.Créez simplement une boucle qui vous donne les octets que vous voulez et placez-la derrière un tuyau ou un tuyau nommé. Il se comportera à peu près de la même manière qu'un périphérique de caractères (ne gaspillera pas les cycles de processeur lorsqu'il est inactif):
Et si vous voulez le super-optimiser, vous pouvez utiliser le code C ci-dessous:
compiler et exécuter
Test de performance:
2,1 Go / s sur ma machine (même légèrement plus rapide que
cat /dev/zero | pv -a >/dev/null
)la source
argc == 1+1
au lieu deagrc == 2
?0 XOR X == X
.Lisez les zéros, traduisez chaque zéro à votre modèle!
Nous lisons zéro octet
/dev/zero
et utilisonstr
pour appliquer un masque de bits à chacun des octets en traduisant chaque octet zéro:Octal 176 est le code ascii de
~
, donc nous obtenons 10~
. (Le$
à la fin de la sortie indique dans mon shell qu'il n'y avait pas de fin de ligne - cela pourrait être différent pour vous)Créons donc des
0xFF
octets: Hex0xFF
est octal0377
. Le zéro de tête est omis pour latr
ligne de commande; À la fin,hexdump
est utilisé pour rendre la sortie lisible.Vous devez utiliser les codes octaux des caractères ici, au lieu de l'hexadécimal. C'est donc la plage de
\000
à octal\377
(identique à0xFF
).Utilisez
ascii -x
etascii -o
pour obtenir un tableau des caractères avec des numéros d'index hexadécimaux ou octaux.(Pour un tableau avec décimal et hexadécimal, juste
ascii
).Tres rapide
Il fonctionne assez rapidement, comparé à la simple utilisation des zéros: il
cat /dev/zero
n'est que quatre fois plus rapide, alors qu'il peut faire un usage parfait de la mise en mémoire tampon d'E / S, ce quitr
n'est pas possible.la source
Cela dépend de ce que vous voulez faire avec les données et de la flexibilité avec laquelle vous souhaitez les utiliser.
Dans le pire des cas, si vous avez besoin de vitesse, vous pouvez faire la même chose que / dev / zero, et simplement compiler les périphériques / dev / one, / dev / two, .. / dev / fourtytwo .. et ainsi de suite.
Dans la plupart des cas, il devrait être préférable de créer les données directement là où elles sont nécessaires, donc à l'intérieur d'un programme / script en tant que constante. Avec plus d'informations, les gens pourraient mieux vous aider.
la source
Boucle d'impression infinie
Remplacez
\u00
par l'octet que vous voulez.while true ; do printf "\u00" ; done | yourapp
Code C ++:
Compiler: remplacez
Byte
avec la valeur que vous voulez.g++ -O3 -o bin file.cpp -D Byte=0x01
Utilisation
./bin | yourapp
la source