Ein weiteres Perl:
perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_'
Beweis:
$ echo ABBBAAAABBBBBABBABBBABBB | \
perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_' | \
od -tx1
0000000 70 fb 77
0000003
Das obige liest die Eingabe zeilenweise. Es liegt an Ihnen, sicherzustellen, dass die Linien genau so sind, wie sie sein sollen.
Bearbeiten: Die umgekehrte Operation:
#!/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 );
Dies liest jeweils ein Byte der Eingabe.
Änderung 2: Einfachere Umkehroperation:
perl -pe 'BEGIN { $/ = \3; $\ = "\n"; binmode \*STDIN } $_ = unpack "B*"; tr/01/AB/'
Das obige liest jeweils 3 Bytes aus STDIN
(aber Empfang von EOF
mitten in einer Sequenz ist kein fatales Problem).
{ printf '2i[q]sq[?z0=qPl?x]s?l?x'
tr -dc AB | tr AB 01 | fold -b24
} <infile | dc
Mit der folgenden Aussage hat @lcd047 meinen früheren Zustand der Verwirrung ziemlich gut auf den Punkt gebracht:
Sie scheinen von der Ausgabe von od
verwirrt zu sein . Verwenden Sie od -tx1
Bytes anschauen. od -x
liest Wörter und auf Little-Endian-Maschinen, die Bytes tauschen. Ich habe den obigen Austausch nicht genau verfolgt, aber ich denke, Ihre ursprüngliche Version war korrekt, und Sie müssen sich überhaupt nicht mit der Byte-Reihenfolge herumschlagen. Verwenden Sie einfach od -tx1
, nicht od -x
.
Jetzt fühle ich mich sehr besser - die frühere Notwendigkeit für dd conv=swab
hat mich den ganzen Tag genervt. Ich konnte es nicht festnageln, aber ich wusste, dass etwas damit nicht stimmte. Es in meiner eigenen Dummheit wegerklären zu können, ist sehr beruhigend - zumal ich etwas gelernt habe.
Wie auch immer, das löscht jedes Byte, das nicht [AB]
ist , dann tr
Fügen Sie diese an [01]
an entsprechend vor fold
den resultierenden Stream mit 24 Bytes pro Zeile. dc
?
liest Zeile für Zeile, prüft, ob die Eingabe etwas enthält, und wenn ja, P
gibt den Byte-Wert dieser Zahl nach stdout aus.
Ab man dc
:
-
P
- Hält den Wert ganz oben auf dem Stapel. Wenn es sich um einen String handelt, wird er einfach ohne abschließenden Zeilenumbruch ausgegeben. Andernfalls handelt es sich um eine Zahl, und der ganzzahlige Teil ihres Absolutwerts wird als "Basis (
UCHAR_MAX+1
)" Byte-Stream.
- Hält den Wert ganz oben auf dem Stapel. Wenn es sich um einen String handelt, wird er einfach ohne abschließenden Zeilenumbruch ausgegeben. Andernfalls handelt es sich um eine Zahl, und der ganzzahlige Teil ihres Absolutwerts wird als "Basis (
-
i
- Entfernt den Wert von der Spitze des Stapels und verwendet ihn, um den Eingaberadix festzulegen.
etwas Shell-Automatisierung
Hier ist eine Shell-Funktion, die ich basierend auf dem oben Gesagten geschrieben habe und die in beide Richtungen gehen kann:
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
)
Dadurch wird ABABABA
übersetzt Zeug zu Bytes mit -B
, also können Sie einfach Folgendes tun:
ABdc -B <infile
Aber es übersetzt beliebige Eingaben in 24 ABABABA
Bit-pro-Byte codierte Zeichenfolgen - in der gleichen Form wie beispielsweise in der Frage dargestellt - mit -B
.
seq 5 | ABdc -A | tee /dev/fd/2 | ABdc -B
AABBAAABAAAABABAAABBAABA
AAAABABAAABBAABBAAAABABA
AABBABAAAAAABABAAABBABAB
AAAABABAAAAAAAAAAAAAAAAA
1
2
3
4
5
Für -A
Ausgabe Ich rollte in cut
, expand
, und od
hier, worauf ich gleich noch eingehen werde, aber ich habe auch noch einen weiteren dc
hinzugefügt . Ich habe Zeile für Zeile ?
weggelassen lesen Sie dc
Skript für eine andere Methode, die ein Array gleichzeitig mit f
bearbeitet - Dies ist ein Befehl, der den f
druckt Voll dc
Befehlsstapel nach stdout. Natürlich, weil dc
ist ein Stack-orientiertes last-in, first-out Art der Anwendung, das bedeutet, dass der f
ull-stack wird in der umgekehrten Reihenfolge ausgegeben, in der er eingegeben wurde.
Dies könnte ein Problem sein, aber ich verwende einen anderen dc
sowieso mit einem o
Ausgaberadix auf 100000000 gesetzt um das ganze 0-Padding so einfach wie möglich zu handhaben. Und wenn es das last-in, first-out des anderen liest Stream, es wendet diese Logik noch einmal darauf an, und es kommt alles in der Wäsche heraus. Die beiden dc
s arbeiten wie folgt zusammen:
{ 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
...der Stream nach dem ersten 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
...pro Sekunde tee
, wie von dc
geschrieben zu 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.
...und die Ausgabe des zweiten dc
schreibt ist...
01110011
01101111
01101101
01100101
00100000
01100100
01100001
01110100
01100001
00001010
Von dort die Funktion paste
s es auf
01110011 01101111 01101101
01100101 00100000 01100100
01100001 01110100 01100001
00001010
...expand
s
01110011 01101111 01101101
01100101 00100000 01100100
01100001 01110100 01100001
00001010
...cut
s entfernt alle außer Bytes 2-9,12-19,22-29
...
011100110110111101101101
011001010010000001100100
011000010111010001100001
00001010
...und tr
fügt A
an und Einsen an B
...
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
In der letzten Zeile können Sie meine Hauptmotivation für die Aufnahme von expand
sehen - Es ist ein so leichter Filter und stellt sehr einfach sicher, dass jede geschriebene Sequenz - auch die letzte - auf 24 codierte Bits aufgefüllt wird. Wenn dies umgekehrt wird, werden die Zeichenfolgen zu -B
decodiert yte-Wert gibt es zwei angehängte NULs:
ABdc -B <<\IN | od -tc
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
IN
...wie Sie sehen können...
0000000 s o m e d a t a \n \0 \0
0000014
Daten aus der realen Welt
Ich habe damit gespielt und es mit einigen einfachen, realistischen Streams ausprobiert. Ich habe diese aufwendige Pipeline für gestaffelte Berichte erstellt...
{ ###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
Allerdings habe ich hier keine gute Grundlage für einen Leistungsvergleich. Ich kann nur sagen, dass ich zu diesem Test getrieben wurde, als ich (vielleicht naiv) war beeindruckt genug, um dies zu tun von...
man man | ABdc -A | ABdc -B
...die meinen Terminalbildschirm mit man
gemalt haben 's Ausgabe mit der gleichen wahrnehmbaren Geschwindigkeit, wie es der ungefilterte Befehl tun könnte. Die Ausgabe des Tests war...
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
Erste Tests
Der Rest ist nur ein einfacher Proof of Concept, dass es überhaupt funktioniert...
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