Bashスクリプトでcallを使用してサーバーからファイルをダウンロードしますcurl
。さて、ファイルが完全にダウンロードされたことを確認したいと思います。この目的のために、ダウンロードファイルとヘッダーサイズを比較しましたContent-Length
。どちらも同じですが、次のエラーが発生します。
")syntax error: invalid arithmetic operator (error token is "
Bashスクリプトの一部:
remote_size=$(curl -kI "${HEADERS[@]}" "$url" | grep -i content-length | awk '{print $2}')
local_size=$(stat --format=%s "$dest/$file")
if (( remote_size == local_size )); then
echo "File is complete" >&2
elif (( remote_size > local_size )); then
echo "Download is incomplete" >&2
elif (( remote_size < local_size )); then
echo "Remote file shrunk -- probably should delete local and start over" >&2
fi
からインスピレーションを受ける:https://stackoverflow.com/questions/37885503/check-if-curl-incremental-continue-at-download-is-successful/37885681?
誰でもここで何が問題なのか、解決策を教えてもらえますか?
事前にありがとう
PS:Ubuntu(WSL)でテストしていますが、スクリプトは最終的に組み込みプラットフォームのLinuxに含まれます。欠落している情報があれば教えてください。
答え1
$ curl -sI https://google.com | sed -n '/content-length/l'
content-length: 220\r$
行末のキャリッジリターン文字(別名CR
、、、\r
)を参照してください(行末を表す方法)。 HTTPヘッダ^M
$
sed
CRLFで区切る、Unix行の区切り文字はLFです。
返品Bashや他のKorn様シェルの算術式から削除されていないデータを使用することは、コマンドインジェクションの脆弱性です。、ここには別の問題があります。つまり、-k
aka--insecure
オプションを使用すると、MitM攻撃者は応答にランダムなヘッダーを挿入できます。
GNUシステムでは、次のものを使用できます。
local_size=$(stat -Lc %s -- "$dest/$file") || die
remote_size=$(curl -sI -- "$url" | LC_ALL=C grep -Piom1 '^content-length:\s*\K\d+') ||
die "No content-length"
case $((local_size - remote_size)) in
(0) echo same;;
(-*) echo remote bigger;;
(*) echo local bigger;;
esac
\d+
Cロケールから一致するもののみを返すことで、10進数のremote_size
ASCII番号のみを含めることでACEの脆弱性を排除します。
この GNU コマンドに対応する標準はgrep
次のとおりです。
LC_ALL=C sed '/^[Cc][Oo][Nn][Tt][Ee][Nn][Tt]-[Ll][Ee][Nn][Gg][Tt][Hh]:[[:space:]]*\([0-9]\{1,\}\).*/!d;s//\1/;q'
ヘッダーが見つからない場合は返されません。間違った終了ステータスはgrep
このような操作を実行するため、さらに確認する必要があります[ -n "$remote_size" ]
。
die
上記は次のとおりです。
die() {
[ "$#" -eq 0 ] || printf>&2 '%s\n' "$@"
exit 1
}
(使用したいロギングメカニズムに合わせて調整してください)。
また、実際にはこれが発生する可能性は低いですが、ヘッダーが折りたたまれることがあることに注意してください。たとえば、コンテンツ長ヘッダーは次のように返されます。
Content-Length:<CR>
123456<CR>
ヘッダ値を抽出する1つの方法は、formail
RFC822ヘッダを処理するように特別に設計されたツールを使用することです。
remote_size=$(curl... | formail -zcx content-length -U content-length)
の場合、ヘッダが複数ある-U content-length
場合はContent-Length
最後のヘッダが返されます。上記のように最初の項目を返すように-U
変更します。-u
grep -m1
ACE の脆弱性を回避するには、結果を削除するか、代わりに[
's( [[...]]
's! ではない) -lt
//-eq
演算子を使用する必要があります。-gt
((...))
バージョン7.84.0以降では、次のようにこのヘッダーの値を直接提供するcurl
こともできます。curl
remote_size=$(curl -w '%header{content-length}' -sIo /dev/null -- "$url") || die
テストを通して見つけたもの
- ヘッダーが複数回表示される場合、最初のヘッダーの値のみが返されます。
- 値が数字で始まらない場合(オプションでaで始まる)、文句を言いますが、
+
その後に渡されたすべての文字を削除する必要があります。 - ヘッダーの縮小をサポートしますが、最初の行にNULL値を持つコンテンツの長さは拒否されます。