로컬로 또는 네트워크 위치에서 파이프를 통해 압축 파일을 보내고 있습니다. 수신 측에서는 압축 유형을 감지하고 적절한 압축 해제 유틸리티(gzip, bzip2, xz 등)를 사용하여 압축을 풀고 싶습니다. 명령은 다음과 같습니다.
현지의:
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
명령의 인수는 동일하지만 다른 압축 해제 도구에서는 다를 수 있습니다.
다음은 원격 호스트에서 얻은 파일의 압축을 푸는 버전입니다.
#! /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
)