sh
ファイルがメモリに収まらない場合でも実行できるように、巨大な自動生成シェルスクリプトを書く良い技術はありますか?また、シェル自体がheredocをメモリに一度に読み取らないという保証はありますか?実際には、どのシェルがこの文書をメモリに保存せず、sh
これを行うために任意のシステムの一貫性に頼ることができますか?
私はGNUについて読んでいますshar
が、大きすぎてメモリに入ることができないファイルにGNUを使用できるかどうか疑問に思います。コンテンツを保存するためにheredocsを使用してください。
sed -e 's/^X//' << 'SHAR_EOF' | uudecode &&
Msome binary content
Xsome text content
SHAR_EOF
shar
ただし、そのようなheredocが複数あり、スクリプトの一部が実行される前に解析する必要がある可能性があるスクリプトの最後に、いくつかの固定された非heredocコンテンツがあります。シェルがスクリプト全体を解析しない場合、最初のコマンドを実行する前に間違ったスクリプトを拒否することはできません。
以下はsharアーカイブの末尾のシェルコメントの一部です。
...
else
test `LC_ALL=C wc -c < 'a.binary'` -ne 126472 && \
${echo} "restoration warning: size of 'a.binary' is not 126472"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0
答え1
シェルがここのドキュメント全体をメモリにロードするかどうかについての保証はありません。巨大なスクリプトは一般的ではないため、シェル実装者はこの状況を最適化する可能性はありません。実行が開始される前にスクリプト全体をメモリにロードせずに実行することはやや望ましくありませんが、すべての汎用シェルは完全にロードされる前に実行されます。つまり、実行中にスクリプトファイルが変更されるとゴミになります。
実験的に、Debianでは、jessie、dash、bash、mksh、およびzshはこのドキュメントの130kBをメモリにロードしますが、ksh93は追加のメモリを割り当てずに64kBチャンクをコピーします。したがって、メモリに合わないドキュメントを使用する唯一の方法は、スクリプトがksh93(またはksh88)を使用して実行されていることを確認することです。これを行う前に、他のバージョンもあることを確認してください。すべてを確認したわけではありません。 ksh まだバージョンは同じように動作します。
移植性を高めるためにできることは、すべてのデータをスクリプトの最後に置き、それを使用してtail -c $offset
ペイロードを抽出することです。通常のシェルは、スクリプトを実行する前にメモリにスクリプトを完全にロードしないため、実際に機能します。このアプローチの利点は、ペイロードがバイナリである可能性があることです。この文書には、heredoc 末尾の文字列または null バイトを含めることはできません。
スクリプトが変更できない場合は、ペイロードオフセットをハードコードできます。それ以外の場合は、スクリプトの最後に区別可能なマーカーを配置し、awkを使用してその場所を確認できます。
offset=$(awk '{offset += length($0) + 1}
$0 == "# payload starts here (do not remove this magic comment)" {
print offset; exit
}')
…
tail -c "$offset" <"$0" — …
…
# payload starts here (do not remove this magic comment)
複数のペイロードがある場合、それらを抽出するにはより複雑なコマンドが必要です。head -c
これはすべてのUNIXバリアントに存在するわけではありません。これを使用してdd ibs=1 count=$bytes
同じ効果を得ることができますが、多くのdd
実装は一度に1バイトをコピーするため、非常に遅くなる可能性があります。 tarアーカイブを添付し、名前でファイルを抽出することをお勧めします。