パイプを介して動作する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
ギガバイトサイズのシェルスクリプトを持っているという考えは私には言わないようです。だからデータを別のファイルに入れてください。
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)、省略できます。
「一括データ」を数量化してみてください。お客様のニーズに合わせてこれをテストしましたが、10 MBに疲れました(今日見られるより小さなラムでは、ずっと前のことです)。
sed が間違っている可能性があります。各行の最初のXのみを置き換えます。次のような場合もあります。 sed 's/X//g'
tarは抽出するものはありません。標準入力を読むには、アーカイブ名(おそらく「-」)が必要です。
最終版が間違っています。パイプはまったくリダイレクトされないため、sedがコマンドラインからstdinを読むと永久に停止します。 XXQAAgAD/で始まると、コマンド名として解釈されます。
シェルスクリプトに多くの静的データを含める理由は不明です。これがデータファイルとパイプの目的です。ここで解決しようとしている具体的な問題は何ですか?
もちろん、tarを介してアーカイブされたファイル、xzで圧縮されたファイル、base64でエンコードされたファイルが電子メールで送信された場合、これは完全に理解されます。シェルスクリプトにデータを挿入する部分は除外されます。そして最初のXビットを削除します。
答え3
here-docがなくても、標準入力でスクリプトを使用できる限りうまく機能します。 stdinを検索できる場合、Bashは実行前に最初の行の終わりを検索します。それ以外の場合は、一度に1文字ずつ読み込み、ストリームを同じ場所に配置します。しかし、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
ファイルを別々のファイルに転送する場合は、スペースが少なくなります。つまり、私たちはこのようなスクリプトについて話しているので、可能であればそうではないと仮定する必要があります。