쉘 명령에 대한 입력으로 대량의 데이터 전달

쉘 명령에 대한 입력으로 대량의 데이터 전달

파이프를 통해 작동하는 bash 셸(비대화형)을 사용하여 많은 양의 데이터를 셸 명령에 전달하려고 합니다. 지금까지는 안정적으로 작동할 수 없습니다.

예를 들어 여기 문서를 사용하면 다음과 같습니다.

(sed s/X//|base64 -d|lzcat|tar x) << EOF
XXQAAgAD//////////wAzG+wBunDDREwYD51KYXL50sahXmBTOGSine7WC0RATjpIrem5ygsQWKoZ
XwhPmkJAuCyqnO1KQAoFruXjSOsR3KJY+zHvzYFOgpl3ZJa+1+b0cB0w2vYzj53qplKMTjRkchPnr
XZ/nbloA=
EOF

그러나 많은 양의 데이터의 경우 bash는 명령에 전달하기 전에 모든 데이터를 메모리에 로드하려고 시도하기 때문에 작동하지 않습니다.

반면에 여기 문서 없이 직접 이 작업을 수행하면 명령에 직접 전달되어야 하지만 셸에서는 예측할 수 없는 수의 행을 셸 명령으로 해석하는 것 같습니다.

(sed s/X//|base64 -d|lzcat|tar x)
XXQAAgAD//////////wAzG+wBunDDREwYD51KYXL50sahXmBTOGSine7WC0RATjpIrem5ygsQWKoZ
XwhPmkJAuCyqnO1KQAoFruXjSOsR3KJY+zHvzYFOgpl3ZJa+1+b0cB0w2vYzj53qplKMTjRkchPnr
XZ/nbloA=

나는 이것이 비대화형 쉘이 입력을 버퍼링하는 방식과 관련이 있다고 생각합니다.

데이터를 전달하는 셸로 돌아갈 필요가 없으므로 동작을 예측할 수 있다면 후자와 같은 솔루션이 실현 가능합니다.

답변1

기가바이트 크기의 쉘 스크립트를 갖는다는 생각은 제게는 말도 안되는 것 같습니다. 그러니 데이터를 별도의 파일에 넣으세요.

하나의 파일만 사용하려는 경우: 쉘에 이 데이터를 무시하도록 지시하십시오. 파일 끝에 넣는 .셸은 파일이 끝날 때까지 exit(적어도 ) 읽지 않습니다.bash

외부 명령을 사용하여 파일에서 데이터를 추출하고 이를 예상 명령에 전달합니다.

#! /bin/bash

do_something_with_the_data () {
        wc
}

test -f "$0" || exit 3

awk '/^DATABLOCK-1$/ { run=1; next; }; run==0 { next; }; '\
'$0=="" { exit; }; { print; }' "$0" |
        do_something_with_the_data

awk '/^DATABLOCK-2$/ { run=1; next; }; run==0 { next; }; '\
'$0=="" { exit; }; { print; }' "$0" |
        do_something_with_the_data

exit 0

DATABLOCK-1
foo bar baz

DATABLOCK-2
x
y
z

답변2

셸에 데이터를 확장하고 바꾸도록 지시하는 << EOF를 전달하고 있습니다. 이는 두통을 유발할 수 있으며 의도하지 않은 결과를 초래할 수 있습니다. 데이터의 쉘 구문 분석을 비활성화하려면 리디렉션을 인용해야 합니다(예: << 'EOF'). 그러나 종료 EOF는 아닙니다. EOF가 스크립트의 마지막 항목인 경우(IIRC) 생략할 수 있습니다.

"대량 데이터"를 수량화해 보세요. 고객 요구에 맞춰 이것을 테스트했지만 10MB에 지쳤습니다(오늘날 볼 수 있는 더 작은 램에서는 오래 전의 일입니다).

sed가 틀렸을 수도 있습니다. 각 행의 초기 X만 대체합니다. 다음을 원할 수도 있습니다: sed 's/X//g'

tar는 추출할 것이 없습니다. 표준 입력을 읽으려면 아카이브 이름(아마도 "-")이 필요합니다.

최종 버전이 잘못되었습니다. 파이프는 전혀 리디렉션되지 않으므로 sed가 명령줄에서 stdin을 읽으면 영원히 정지됩니다. XXQAAgAD/로 시작하면 명령 이름으로 해석됩니다.

쉘 스크립트에 많은 정적 데이터를 포함시키려는 이유가 명확하지 않습니다. 이것이 바로 데이터 파일과 파이프의 용도입니다. 여기서 해결하려는 구체적인 문제는 무엇입니까?

물론, tar를 통해 보관된 파일, xz로 압축된 파일, base64로 인코딩된 파일이 이메일로 전송된 경우 이 모든 것이 완벽하게 이해됩니다. 쉘 스크립트에 데이터를 삽입하는 부분은 제외됩니다. 그리고 첫 번째 X 비트를 제거하십시오.

답변3

here-doc가 없어도 표준 입력에서 스크립트를 사용할 수 있는 한 잘 작동합니다. stdin을 검색할 수 있으면 Bash는 실행하기 전에 첫 번째 줄의 끝을 검색합니다. 그렇지 않으면 한 번에 한 문자씩 읽고 스트림을 같은 위치에 둡니다. 그러나 Dash(Debian의 /bin/sh)는 그렇지 않습니다.

여기에 있는 내용은 파일 이름이 지정된 gzip으로 압축된 tar 파일입니다 hello.txt(질문의 내용과 다름).

$ ls
data.sh
$ cat data.sh 
sed -e 's/^X//' | base64 -d | tar -zxf -
XH4sIANuo0l4AA+3RMQrCQBCF4ak9xZ5AZmc363mCCglEAusoHl8TxM4iRZLm/5rHwCseTHcdhvHo
XL5f16EfJecp4anS+NX1zViSmUnJjOVkUjWbFJOiKm34ed29rCNL7s6/e/u2dL3W8bTFoW930/8Pe
XKwAAAAAAAAAAAAAAAAAAS70BbZqA2QAoAAA=
$ bash < data.sh 
$ cat hello.txt 
hello

또한보십시오:

tar -f -시스템(GNU tar의 경우 컴파일 방법)에 따라 기본 입력이 테이프 드라이브일 가능성이 높으므로 사용하고 싶을 수도 있습니다 .

그러나 실제로 사용자에게 전송한 일부 코드를 실행하도록 요청하는 것과 같은 자동 추출 쉘 스크립트에는 수상한 점이 있습니다. 또한 Base-64 인코딩은 데이터를 크게 확장하므로 tar파일을 별도의 파일로 전송하는 경우 공간을 덜 사용할 수 있습니다. 즉, 우리가 이와 같은 스크립트에 대해 이야기하고 있기 때문에 가능하다면 그렇지 않다고 가정해야 합니다.

관련 정보