Otra perlita:
perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_'
Prueba:
$ echo ABBBAAAABBBBBABBABBBABBB | \
perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_' | \
od -tx1
0000000 70 fb 77
0000003
Lo anterior lee la entrada una línea a la vez. Depende de usted asegurarse de que las líneas sean exactamente lo que se supone que deben ser.
Editar: La operación inversa:
#!/usr/bin/env perl
binmode \*STDIN;
while ( defined ( $_ = getc ) ) {
$_ = unpack "B*";
tr/01/AB/;
print;
print "\n" if ( not ++$cnt % 3 );
}
print "\n" if ( $cnt % 3 );
Esto lee un byte de entrada a la vez.
Edición 2: Operación inversa más simple:
perl -pe 'BEGIN { $/ = \3; $\ = "\n"; binmode \*STDIN } $_ = unpack "B*"; tr/01/AB/'
Lo anterior lee 3 bytes a la vez desde STDIN
(pero recibiendo EOF
en medio de una secuencia no es un problema fatal).
{ printf '2i[q]sq[?z0=qPl?x]s?l?x'
tr -dc AB | tr AB 01 | fold -b24
} <infile | dc
Al hacer la siguiente declaración, @lcd047 ha dado en el clavo con mi anterior estado de confusión:
Pareces estar confundido por la salida de od
. Usa od -tx1
para mirar bytes. od -x
lee palabras, y en máquinas little endian que intercambian bytes. No seguí de cerca el intercambio anterior, pero creo que su versión inicial era correcta y no necesita meterse con el orden de bytes en absoluto. Solo usa od -tx1
, no od -x
.
Ahora bien, esto me hace sentir mucho mucho mejor:la necesidad anterior de dd conv=swab
me estuvo molestando todo el día. No pude fijarlo, pero sabía que había algo mal con él. Poder explicarlo con mi propia estupidez es muy reconfortante, especialmente porque aprendí algo.
De todos modos, eso eliminará todos los bytes que no sean [AB]
, luego tr
traducirlos a [01]
en consecuencia, antes de fold
ing el flujo resultante a 24 bytes por línea. dc
?
lee una línea a la vez, verifica si la entrada contenía algo y, si es así, P
imprime el valor en bytes de ese número en la salida estándar.
Desde man dc
:
-
P
- Extrae el valor en la parte superior de la pila. Si es una cadena, simplemente se imprime sin una nueva línea al final. De lo contrario, es un número, y la parte entera de su valor absoluto se imprime como una base "(
UCHAR_MAX+1
)" flujo de bytes
- Extrae el valor en la parte superior de la pila. Si es una cadena, simplemente se imprime sin una nueva línea al final. De lo contrario, es un número, y la parte entera de su valor absoluto se imprime como una base "(
-
i
- Retira el valor de la parte superior de la pila y lo usa para establecer la base de entrada.
algo de automatización de shell
Aquí hay una función de shell que escribí basada en lo anterior que puede funcionar en ambos sentidos:
ABdc()( HOME=/dev/null A='[fc[fc]]sp[100000000o]p2o[fc]' B=2i
case $1 in
(-B) { echo "$B"; tr AB 01 | paste -dP - ~ ; }| dc;;
(-A) { echo "$A"; od -vAn -tu1 | paste -dlpx - ~ ~ ~; }| dc|
dc | paste - - - ~ | expand -t10,20,30 |
cut -c2-9,12-19,22-29 | tr ' 01' AAB ;;
(*) set '' "$1";: ${1:?Invalid opt: "'$2'"} ;;
esac
)
Eso traducirá el ABABABA
cosas a bytes con -B
, así que solo puedes hacer:
ABdc -B <infile
Pero traducirá la entrada arbitraria a 24 ABABABA
cadenas codificadas bit por byte, en la misma forma que se presenta, por ejemplo, en la pregunta, con -B
.
seq 5 | ABdc -A | tee /dev/fd/2 | ABdc -B
AABBAAABAAAABABAAABBAABA
AAAABABAAABBAABBAAAABABA
AABBABAAAAAABABAAABBABAB
AAAABABAAAAAAAAAAAAAAAAA
1
2
3
4
5
Para -A
salida que rodé en cut
, expand
y od
aquí, que abordaré en un minuto, pero también agregué otro dc
. Dejé caer la línea por línea ?
leer dc
secuencia de comandos para otro método que trabaja una matriz a la vez con f
- que es un comando que imprime el f
completo dc
pila de comandos a la salida estándar. Por supuesto, porque dc
es un último en entrar, primero en salir orientado a la pila tipo de aplicación, eso significa que el f
ull-stack sale en el orden inverso al que entró.
Esto podría ser un problema, pero uso otro dc
de todos modos con un o
base de salida establecida en 100000000 para manejar todo el relleno 0 de la manera más simple posible. Y cuando lee el último en entrar, primero en salir del otro flujo, aplica esa lógica a todo de nuevo, y todo sale en el lavado. Los dos dc
s trabajar en concierto como este:
{ echo '[fc[fc]]sp[100000000o]p2o[fc]'
echo some data |
od -An -tu1 ###arbitrary input to unsigned decimal ints
echo lpx ###load macro stored in p and execute
} | tee /dev/fd/2 | ###just using tee to show stream stages
dc| tee /dev/fd/2 |dc
...la transmisión según el primer tee
...
[fc[fc]]sp[100000000o]pc2o[fc] ###dc's init cmd from 1st echo
115 111 109 101 32 100 97 116 97 10 ###od's output
lpx ###load p; execute
...por el segundo tee
, como está escrito desde dc
a dc
...
100000000o ###first set output radix
1010 ###bin/rev vs of od's out
1100001 ###dc #2 reads it in, revs and pads it
1110100
1100001
1100100
100000
1100101
1101101
1101111 ###this whole process is repeated
1110011 ###once per od output line, so
fc ###each worked array is 16 bytes.
...y la salida que el segundo dc
escribe es...
01110011
01101111
01101101
01100101
00100000
01100100
01100001
01110100
01100001
00001010
A partir de ahí la función paste
está en
01110011 01101111 01101101
01100101 00100000 01100100
01100001 01110100 01100001
00001010
...expand
s
01110011 01101111 01101101
01100101 00100000 01100100
01100001 01110100 01100001
00001010
...cut
s todo menos bytes 2-9,12-19,22-29
...
011100110110111101101101
011001010010000001100100
011000010111010001100001
00001010
...y tr
traduce A
y unos a B
...
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
Puede ver en la última línea mi motivación principal para incluir expand
- es un filtro tan liviano, y asegura muy fácilmente que cada secuencia escrita, incluso la última, se rellene a 24 bits codificados. Cuando se invierte el proceso y las cadenas se decodifican a -B
yte-value, hay dos NUL adjuntos:
ABdc -B <<\IN | od -tc
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
IN
...como puedes ver...
0000000 s o m e d a t a \n \0 \0
0000014
datos del mundo real
Jugué con él y lo probé con algunas transmisiones simples y realistas. Construí esta canalización elaborada para informes organizados...
{ ###dunno why, but I often use man man
( ###as a test input source
{ man man | ###streamed to tee
tee /dev/fd/3 | ###branched to stdout
wc -c >&2 ###and to count source bytes
} 3>&1 | ###the branch to stdout is here
ABdc -A | ###converted to ABABABA
tee /dev/fd/3 | ###branched again
ABdc -B ###converted back to bytes
times >&2 ###the process is timed
) | wc -c >&2 ###ABdc -B's output is counted
} 3>&1| wc -c ###and so is the output of ABdc -A
Sin embargo, aquí no tengo ninguna buena base para comparar el rendimiento. Solo puedo decir que fui llevado a esta prueba cuando estaba (quizás ingenuamente) lo suficientemente impresionado como para hacerlo por...
man man | ABdc -A | ABdc -B
...que pintó la pantalla de mi terminal con man
La salida de a la misma velocidad perceptible que el comando sin filtrar podría hacer. El resultado de la prueba fue...
37595 ###source byte count
0m0.000000s 0m0.000000s ###shell processor time nil
0m0.720000s 0m0.250000s ###shell children's total user, system time
37596 ###ABdc -B output byte count
313300 ###ABdc -A output byte count
pruebas iniciales
El resto es solo una prueba de concepto más simple de que funciona...
printf %s ABBBAAAABBBBBABBABBBABBB|
tee - - - - - - - -|
tee - - - - - - - - - - - - - - - |
{ printf '2i[q]sq[?z0=qPl?x]s?l?x'
tr -dc AB | tr AB 01 | fold -b24
} | dc | od -tx1
0000000 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000020 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000040 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000060 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000100 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000120 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000140 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000160 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000200 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000220 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000240 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000260 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000300 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000320 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000340 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000360 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000400 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000420 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000440 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000460 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000500 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000520 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000540 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000560 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000600 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 0000620 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 0000640 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 70 fb 77 0000660