나는 무수한 이유로 C ++ 코드를 bash로 번역하려고 애매하게 노력하고 있습니다.
이 코드는 바이너리로 완전히 작성되고 구조화 된 내 서브 필드에 특정한 파일 유형을 읽고 조작합니다. 첫 번째 이진 관련 작업은 헤더의 첫 988 바이트를 그대로 그대로 복사 한 다음 나머지 정보를 생성 할 때 계속 쓸 수있는 출력 파일에 넣는 것입니다.
현재 솔루션이 작동하지 않는다고 확신하며 실제로이를 결정하는 좋은 방법을 찾지 못했습니다. 실제로 올바르게 작성 되었더라도이를 테스트하기 위해 어떻게 테스트해야하는지 알아야합니다!
이것이 내가 지금하고있는 일입니다.
hdr_988=`head -c 988 ${inputFile}`
echo -n "${hdr_988}" > ${output_hdr}
headInput=`head -c 988 ${inputTrack} | hexdump`
headOutput=`head -c 988 ${output_hdr} | hexdump`
if [ "${headInput}" != "${headOutput}" ]; then echo "output header was not written properly. exiting. please troubleshoot."; exit 1; fi
hexdump / xxd를 사용하여 파일 의이 부분을 확인하면 대부분을 읽을 수는 없지만 문제가있는 것 같습니다. 그리고 비교를 위해 작성한 코드는 두 문자열이 동일한 지 여부 만 알려주고 원하는 방식으로 복사되지는 않습니다.
bash에서 이것을 수행하는 더 좋은 방법이 있습니까? 파일을 그대로 그대로 복사하기 위해 이진 바이트를 기본 이진으로 복사 / 읽을 수 있습니까? (그리고 변수로 저장하는 것이 이상적임).
답변
쉘 스크립트에서 낮은 수준의 바이너리 데이터를 다루는 것은 일반적으로 나쁜 생각입니다.
bash
변수는 바이트 0을 포함 할 수 없습니다 zsh
. 변수에 해당 바이트를 저장할 수있는 유일한 쉘입니다.
어쨌든 명령 인수 및 환경 변수는 execve
시스템 호출에 전달되는 NUL 구분 문자열이므로 해당 바이트를 포함 할 수 없습니다 .
또한 다음을 참고하십시오.
var=`cmd`
또는 현대적인 형태 :
var=$(cmd)
의 출력에서 모든 후행 줄 바꿈 문자를 제거합니다 cmd
. 따라서 이진 출력이 0xa 바이트로 끝나면에 저장 될 때 엉망이됩니다 $var
.
여기에서로 인코딩 된 데이터를 저장해야합니다 xxd -p
.
hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"
다음과 같은 도우미 기능을 정의 할 수 있습니다.
encode() {
eval "$1"='$(
shift
"$@" | xxd -p -c 0x7fffffff
exit "${PIPESTATUS[0]}")'
}
decode() {
printf %s "$1" | xxd -p -r
}
encode var cat /bin/ls &&
decode "$var" | cmp - /bin/ls && echo OK
xxd -p
출력은 1 바이트를 2 바이트로 인코딩하므로 공간 효율적이지 않지만 조작을보다 쉽게 수행 할 수 있습니다 (연결, 추출). base64
4에서 3 바이트를 인코딩하지만 작업하기 쉽지 않습니다.
ksh93
쉘은 형식 (용도를 코딩하는 내장이 base64
당신이 그와 함께 사용할 수있는) read
및 printf
/ print
유틸리티 :
typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output
이제 쉘 또는 env 변수 또는 명령 인수를 통한 전달이 없으면 사용하는 유틸리티가 모든 바이트 값을 처리 할 수있는 한 괜찮습니다. 그러나 텍스트 유틸리티의 경우 대부분의 비 GNU 구현은 NUL 바이트를 처리 할 수 없으며 멀티 바이트 문자의 문제점을 피하기 위해 로케일을 C로 수정해야합니다. 줄 바꿈 문자가 아닌 마지막 문자는 또한 매우 긴 행 (두 개의 0xa 바이트 사이에서 더 긴 바이트 순서)뿐만 아니라 문제를 일으킬 수 있습니다 LINE_MAX
.
head -c
사용 가능한 곳은 바이트로 작업하기위한 것이므로 여기에서 OK이어야하며 데이터를 텍스트로 취급 할 이유가 없습니다. 그래서
head -c 988 < input > output
괜찮을거야. 실제로 적어도 GNU, FreeBSD 및 ksh93 내장 구현은 괜찮습니다. POSIX는 지정하지 않는 -c
옵션을하지만 말한다 head
길이의 라인을 지원해야한다 (이에 국한되지 LINE_MAX
)
로 zsh
:
IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output
또는:
var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output
에서조차도 NUL 바이트를 포함하는 zsh
경우 $var
, 실행 파일에 전달 된 인수가 NUL로 구분 된 문자열이므로 쉘과는 독립적으로 커널 제한이므로, 위와 같이 zsh
내장 print
또는 함수에 인수로 전달할 수 있지만 실행 파일에 대한 인수로는 전달할 수 없습니다.
답변
나는 무수한 이유로 C ++ 코드를 bash로 번역하려고 애매하게 노력하고 있습니다.
그래 그러나 당신은 그것을하지 않는 매우 중요한 이유를 고려해야합니다. 기본적으로 “bash”/ “sh”/ “csh”/ “ksh”등은 이진 데이터를 처리하도록 설계되지 않았으며 표준 UNIX / LINUX 유틸리티 중 대부분이 아닙니다.
C ++를 고수하거나 이진 데이터를 처리 할 수있는 Python, Ruby 또는 Perl과 같은 스크립팅 언어를 사용하는 것이 좋습니다.
bash에서 이것을 수행하는 더 좋은 방법이 있습니까?
더 좋은 방법은 bash에서하지 않는 것입니다.
답변
귀하의 질문에서 :
헤더의 첫 번째 988 줄을 복사하십시오.
988 줄을 복사하는 경우 바이너리가 아닌 텍스트 파일처럼 보입니다. 그러나 코드는 988 줄이 아닌 988 바이트를 가정하는 것으로 보이므로 바이트가 올바른 것으로 가정합니다.
hdr_988=`head -c 988 ${inputFile}`
echo -n "${hdr_988}" > ${output_hdr}
이 부분은 작동하지 않을 수 있습니다. 우선, ${hdr_988}
명령 줄 인수로 사용하고 명령 줄 인수에 NUL을 포함 할 수 없기 때문에 스트림의 모든 NUL 바이트가 제거됩니다 . 백틱은 공백 제거를 수행하고있을 수도 있습니다 (확실하지 않습니다). (실제로 echo
내장되어 있기 때문에 NUL 제한 이 적용되지 않을 수 있지만 여전히 만족 스럽습니다.)
왜 쉘 변수를 거치지 않고 입력 파일에서 출력 파일로 헤더를 직접 쓰지 않겠습니까?
head -c 988 "${inputFile}" >"${output_hdr}"
또는 더 이식 가능
dd if="${inputFile}" of="${output_hdr}" bs=988 count=1
bash
POSIX 셸이 아닌을 사용한다고 언급 했으므로 프로세스 대체가 가능하므로 테스트로는 어떻습니까?
cmp <(head -c 988 "${inputFile}") <(head -c 988 "${output_hdr}")
마지막으로 백틱 대신에 사용 을 고려하십시오$( ... )
.