two (2)
가능한 문자(및 새 줄)만 포함된 텍스트 파일이 있습니다 \n
. 예:
ABBBAAAABBBBBABBABBBABBB
(크기 24 bytes
)
이것을 어떻게 바이너리, 즉 비트 표현으로 변환하고 가능한 두 값을 각각 0
또는 에 할당합니까 1
?
생성된 바이너리 파일( 0=A
, 1=B
):
011100001111101101110111 # 24 bits - not 24 ASCII characters
16진수 결과 파일:
70FB77 # 3 bytes - not 6 ASCII characters
저는 명령줄 솔루션(어쩌면 dd
,,,,,,,)에 가장 관심이 있습니다. 또한 반대의 경우: 원본을 되돌리는 방법은 무엇입니까?xxd
od
tr
printf
bc
답변1
또 다른 펄:
perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_'
입증하다:
$ echo ABBBAAAABBBBBABBABBBABBB | \
perl -pe 'BEGIN { binmode \*STDOUT } chomp; tr/AB/\0\1/; $_ = pack "B*", $_' | \
od -tx1
0000000 70 fb 77
0000003
위의 내용은 한 번에 한 줄씩 입력을 읽습니다. 선이 의도한 대로 정확하게 표시되는지 확인하는 것은 사용자의 몫입니다.
편집하다:역연산:
#!/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 );
이번에는 한 번에 하나의 입력 바이트를 읽습니다.
편집 2:더 쉬운 역방향 작동:
perl -pe 'BEGIN { $/ = \3; $\ = "\n"; binmode \*STDIN } $_ = unpack "B*"; tr/01/AB/'
위의 내용은 한 번에 3바이트를 읽습니다 STDIN
(그러나 EOF
시퀀스 중간에 수신하는 것은 치명적인 문제가 아닙니다).
답변2
{ printf '2i[q]sq[?z0=qPl?x]s?l?x'
tr -dc AB | tr AB 01 | fold -b24
} <infile | dc
@lcd047은 다음과 같은 진술을 통해 이전의 혼란스러운 상태를 훌륭하게 해결했습니다.
의 출력으로 인해 혼란스러워 보입니다
od
. 바이트를 보는 데 사용됩니다od -tx1
.od -x
리틀 엔디안 시스템에서 단어를 읽고 바이트를 교환합니다. 위의 스왑을 자세히 따르지는 않았지만 초기 버전이 정확하고 엔디안을 전혀 망칠 필요가 없다고 생각합니다. 그냥 사용하세요od -tx1
. 사용하지 마세요od -x
.
이제 이런 생각이 듭니다많은더 나은 - 이전의 필요가 dd conv=swab
하루 종일 나를 괴롭혔습니다. 고칠 수는 없었지만 뭔가 문제가 있다는 걸 알았습니다. 내 자신의 어리석음을 설명할 수 있다는 것은 매우 기뻤습니다. 특히 뭔가를 배웠기 때문입니다.
어쨌든 이는 가 아닌 모든 바이트를 제거하고 그에 따라 해석 [AB]
한 다음 한 줄에 24바이트의 결과 스트림을 생성합니다. 한 번에 한 줄씩 읽고, 입력에 내용이 포함되어 있는지 확인하고, 포함되어 있으면 해당 숫자의 바이트 값을 표준 출력으로 인쇄합니다.tr
[01]
fold
dc
?
P
에서 man dc
:
P
- 스택의 맨 위에 있는 값을 팝합니다. 문자열인 경우 후행 줄 바꿈 없이 간단히 인쇄됩니다. 그렇지 않으면 숫자이고 절대값의 정수 부분은 다음과 같이 인쇄됩니다."에 따르면(
UCHAR_MAX+1
)"바이트 스트림.
- 스택의 맨 위에 있는 값을 팝합니다. 문자열인 경우 후행 줄 바꿈 없이 간단히 인쇄됩니다. 그렇지 않으면 숫자이고 절대값의 정수 부분은 다음과 같이 인쇄됩니다."에 따르면(
i
- 스택 상단에서 값을 팝하고 이를 사용하여 입력 기준을 설정합니다.
일부 쉘 자동화
다음은 위 내용을 기반으로 제가 작성한 셸 함수로, 양방향으로 실행될 수 있습니다.
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
)
이것은 번역됩니다ABABABA
패딩 바이트를 사용하면 -B
다음과 같이 할 수 있습니다.
ABdc -B <infile
그러나 모든 입력을 24로 변환합니다.ABABABA
바이트당 비트로 인코딩된 문자열 - 질문에 제시된 것과 동일한 형식 - w/ -B
.
seq 5 | ABdc -A | tee /dev/fd/2 | ABdc -B
AABBAAABAAAABABAAABBAABA
AAAABABAAABBAABBAAAABABA
AABBABAAAAAABABAAABBABAB
AAAABABAAAAAAAAAAAAAAAAA
1
2
3
4
5
-A
출력 의 경우 여기에 cut
, , 을 expand
추가 했습니다 od
. 잠시 후에 설명하겠지만 또 하나 추가했습니다 . 배열을 하나씩 사용하는 dc
다른 방법으로 스크립트를 한 줄씩 ?
읽는 것을 포기했습니다. time - 이것은 ull 명령 스택을 표준 출력으로 dc
인쇄하는 명령입니다 . f
물론 스택 지향이기 때문에f
dc
dc
후입 선출법애플리케이션 유형. 이는 f
입력된 순서와 반대 순서로 ull-stack이 나타남을 의미합니다.
이것은 문제가 될 수 있지만 dc
어쨌든 다른 것을 사용하고 o
출력 기반을 다음으로 설정합니다.100000000가능한 한 간단하게 모든 0 패딩을 처리하십시오. 다른 사람의 글을 읽을 때후입 선출법흐름, 이 논리를 다시 적용하면 모든 것이 제자리에 놓이게 됩니다. 두 사람은 dc
다음과 같이 함께 작동합니다.
{ 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
...첫 번째 스트림 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
...초당 tee
, dc
부터 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.
...두 번째 쓰기의 결과 dc
는...
01110011
01101111
01101101
01100101
00100000
01100100
01100001
01110100
01100001
00001010
거기에서 함수는 paste
그것을 <tabs>에 배치합니다...
01110011 01101111 01101101
01100101 00100000 01100100
01100001 01110100 01100001
00001010
... expand
s <tabs>를 10개의 열로 구분된 공백으로 변환...
01110011 01101111 01101101
01100101 00100000 01100100
01100001 01110100 01100001
00001010
... cut
바이트를 제외한 모든 것이 사라졌습니다.2-9,12-19,22-29
...
011100110110111101101101
011001010010000001100100
011000010111010001100001
00001010
...그리고 tr
<공백>과 0을 다음과 같이 해석합니다.A
그리고 그것들B
...
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
마지막 줄에서 내가 추가한 주요 동기를 볼 수 있습니다 expand
. 이는 매우 가벼운 필터이며, 작성된 모든 시퀀스(마지막 시퀀스까지 포함)가 24개의 인코딩 비트로 채워지는 것을 쉽게 보장합니다. 프로세스가 반대가 되면 문자열은 -B
두 개의 추가 NUL과 함께 yte 값으로 디코딩됩니다.
ABdc -B <<\IN | od -tc
ABBBAABBABBABBBBABBABBAB
ABBAABABAABAAAAAABBAABAA
ABBAAAABABBBABAAABBAAAAB
AAAABABAAAAAAAAAAAAAAAAA
IN
...보시다시피...
0000000 s o m e d a t a \n \0 \0
0000014
실제 데이터
나는 그것을 가지고 놀면서 간단하고 실제적인 흐름을 시험해 보았습니다. 단계별 보고를 위해 이 복잡한 파이프라인을 구축했습니다.
{ ###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
하지만 여기서는 성능을 비교할 수 있는 좋은 근거가 없습니다. 내가 말할 수 있는 것은 내가 이 시험을 강제로 치르게 되었다는 것뿐이다.(어쩌면 순진한 것일지도)이 일을 할 만큼 인상적이다...
man man | ABdc -A | ABdc -B
man
...필터링되지 않은 명령과 동일한 식별 가능한 속도로 터미널 화면에 출력을 그립니다. 테스트 결과는...
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
예비 테스트
남은 것은 실제로 작동하는 더 간단한 개념 증명입니다.
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
답변3
진주:
my $len = 24;
my $str = "ABBBAAAABBBBBABBABBBABBB\n";
$str =~ s/\s//g;
(my $bin = $str) =~ y/AB/01/;
my $val = oct("0b".$bin);
printf "%s -> %s -> %X\n", $str, $bin, $val;
my ($filename, $fh) = ("temp.out");
# write the file
open $fh, '>', $filename;
print $fh pack("N", $val); # this actually writes 4 bytes
close $fh;
# now read it, and convert back to a string:
open $fh, '<', $filename;
read $fh, my $data, 4;
close $fh;
my $new_val = unpack "N", $data;
my $new_bin = substr unpack("B32", $data), -$len;
(my $new_str = $new_bin) =~ y/01/AB/;
printf "%X -> %s -> %s\n", $new_val, $new_bin, $new_str;
ABBBAAAABBBBBABBABBBABBB -> 011100001111101101110111 -> 70FB77
70FB77 -> 011100001111101101110111 -> ABBBAAAABBBBBABBABBBABBB
lcd047의 완벽한 답변 덕분에 내 대답은 다음과 같습니다.
my $str = "ABBBAAAABBBBBABBABBBABBB\n";
$str =~ s/\s//g;
(my $bin = $str) =~ y/AB/01/;
printf "%s -> %s\n", $str, $bin;
my ($filename, $fh) = ("temp.out");
# write the file
open $fh, '>', $filename;
print $fh pack("B*", $bin);
close $fh;
my $size = -s $filename;
print $size, "\n";
# now read it, and convert back to a string:
open $fh, '<', $filename;
read $fh, my $data, 1024;
close $fh;
my $new_bin = unpack("B*", $data);
(my $new_str = $new_bin) =~ y/01/AB/;
printf "%s -> %s\n", $new_bin, $new_str;
ABBBAAAABBBBBABBABBBABBB -> 011100001111101101110111
3
011100001111101101110111 -> ABBBAAAABBBBBABBABBBABBB
답변4
텍스트 파일의 문자 바꾸기:
sed -i 's/A/0/g' file.in
sed -i 's/B/1/g' file.in
개행 문자를 나타내기 위해 \n을 사용하는 경우 이를 개행 문자로 바꾸십시오.
sed 's/\\n/\'$'\n''/g' file.in
(ABBBAAAABBBBBABBABBBABBB는 011100001111101101110111이 됩니다)
file.in의 ascii(문자열)를 바이너리 파일에 쓸(있는 그대로) 바이너리 데이터로 처리합니다.
data=$(cat file.in)
# replace file
echo $(printf '%x\n' "$((2#$data))") | xxd -r -p > file.out
# or write to existing file without truncating
echo $(printf '%x\n' "$((2#$data))") | xxd -r -p - file.out
(3바이트) 바이너리 파일을 읽으면 다음과 같은 16진수 코드가 제공됩니다.
hd file.out
70fb77
디코딩(역방향)하려면 hd 또는 xxd를 사용하여 바이너리 파일을 읽고 16진수 코드를 바이너리로 변환한 다음 0과 1을 A와 B로 바꿉니다.
우분투 16.04.7에서 테스트되었습니다.