로컬 또는 네트워크 위치에서 파이프를 사용하여 압축 파일을 보내고 있습니다. 그리고 수신 측에서는 압축 유형을 감지하고 적절한 압축 해제 유틸리티(gzip, bzip2, xz..etc)를 사용하여 압축을 풀고 싶습니다. 명령은 다음과 같습니다.
현지의:
cat misteryCompressedFile | [compressionUtility] -d -fc > /opt/files/uncompressedfile
네트워크를 통해:
ssh user@ipaddr "cat misteryCompressedFile" | [compressionUtility] -d -fc > /opt/files/uncompressedfile
제공된 확장자가 없더라도(예: .gz 또는 .bz2) 파일의 처음 몇 개의 16진수 값을 보면 사용된 압축 유형을 알 수 있습니다. 예를 들어, xxd
두 개의 압축 파일의 처음 몇 개의 16진수 값을 확인 하는 경우 1f8b 0808
gzip과 425a 6836
bzip2를 사용합니다.
그러나 파이핑을 계속 사용하려면 첫 번째 수신 바이트를 확인하여 파일의 첫 번째 파일에 대한 적절한 압축 해제 유틸리티를 선택하려면 어떻게 해야 합니까?
따라서 알 수 없는 압축 파일이 gzip 유형인 경우 명령은 다음과 같습니다.
cat misteryCompressedFile | gzip -d -fc > /opt/files/uncompressedfile
알 수 없는 압축 파일이 bzip2 유형인 경우 명령은 다음과 같습니다.
cat misteryCompressedFile | bzip2 -d -fc > /opt/files/uncompressedfile
전체 파일을 다운로드한 다음 압축 해제에 무엇을 사용할지 결정하지 않고도 배관을 통해 그러한 결정을 내릴 수 있습니까?
답변1
예, 전체 파일을 읽지 않고도 파이프라인에서 해당 작업을 수행할 수 있습니다.
이 첫 번째 스크립트 조각은 헤더를 가로채서 검사하고 전달하는 메커니즘을 보여줍니다. 헤더를 stderr(>&2)에 인쇄하지만 출력에는 계속 표시됩니다.
$ echo 0123456789ABCDEF |
(
HEADER=$(dd bs=1 count=4);
printf 'HEADER:%s\n' "$HEADER" >&2;
printf '%s\n' "$HEADER";
cat
)
4+0 records in
4+0 records out
4 bytes (4 B) copied, 8.4293e-05 s, 47.5 kB/s
HEADER:0123
0123456789ABCDEF
$
핵심은 dd
작은 블록 크기의 파일 변환 유틸리티를 사용하는 것입니다 bs=1
.
이를 확장하면 이것이 효과적인 솔루션입니다. 임시 파일을 사용하여 바이너리 헤더를 저장하겠습니다. 두 개의 4바이트 헤더 중 하나가 표시되지 않으면 아무 작업도 수행되지 않습니다.
#!/bin/sh
trap "rm -f /tmp/$$; exit 1" 1 2 3 15
# grab the 1st 4 bytes off the input stream,
# store them in a file, convert to ascii,
# and store in variable:
HEADER=$(
dd bs=1 count=4 2>/dev/null |
tee /tmp/$$ |
od -t x1 |
sed '
s/^00* //
s/ //g
q
'
)
case "$HEADER" in
1f8b0800)
UNCOMPRESS='gzip -d -fc'
;;
425a6839)
UNCOMPRESS='bzip2 -d -fc'
;;
*)
echo >&2 "$0: unknown stream type for header '$HEADER'"
exit 2
;;
esac
echo >&2 "$0: File header is '$HEADER' using '$UNCOMPRESS' on stream."
cat /tmp/$$ - | $UNCOMPRESS
rm /tmp/$$
답변2
전송 시스템에서 사용 file
하고 해당 정보를 사용하여 원격 호스트에서 실행할 압축 해제 명령을 결정합니다.
예를 들어
#! /bin/sh
filetype=$(file misteryCompressedFile)
case "$filetype" in
*gzip*) CMD='gzip' ; ARGS='-d -fc' ;;
*bzip2*) CMD='bzip2' ; ARGS='-d -fc' ;;
*) echo "error: unknown compression type" ; exit 1 ;;
esac
cat misteryCompressedFile | ssh user@ipaddr "$CMD $ARGS > /opt/files/uncompressedfile"
표시된 예에서 gzip
및 bzip2
명령에 대한 ARGS는 동일하지만 다른 압축 해제 도구에서는 다를 수 있습니다.
원격 호스트에서 가져온 파일의 압축을 푸는 버전은 다음과 같습니다.
#! /bin/sh
# set up an anonymous fifo on fd 3 so we can pass the
# output of `file` to the second subshell without risking
# corruption of stdout/stdin
FIFO=$(mktemp -u)
mkfifo "$FIFO"
exec 3<>"$FIFO"
rm -f "$FIFO"
ssh user@ipaddr 'cat misteryCompressedFile' |
(
HEADER=$(dd bs=1 count=20 2> /dev/null |
od -A none -t o1 -w512 |
sed -e 's: :\\:g')
printf "$HEADER" | file --mimetype - | cut -d/ -f2 >&3
printf "$HEADER"
cat
) | (
read -u 3 -r filetype
case "$filetype" in
gzip) CMD='gzip' ; ARGS='-d -fc' ;;
x-bzip2) CMD='bzip2' ; ARGS='-d -fc' ;;
x-xz) CMD='unxz' ; ARGS='' ;;
x-lzma) CMD='lzcat' ; ARGS='' ;;
x-compress) CMD='uncompress' ; ARGS='' ;;
x-lrzip) CMD='lrzcat' ; ARGS='' ;;
*) echo "error: unknown compression type" >&2 ; exit 1 ;;
esac
$CMD $ARGS > /opt/files/uncompressedfile
)