web-dev-qa-db-ja.com

なぜ二重引用符で囲まれた文字列の変数展開に続くバイトが先行するバイトを上書きするのですか?

一部のソフトウェアの最新バージョンをダウンロードするためのシェルスクリプトを書いています。 curlの出力を解析した後、正確なバージョン文字列を見つけるためにいくつかのステップを実行します(これを書いている時点では0.65.3です):

(以下のすべてのコードサンプルで、>は私のプロンプトです。Bash3.2またはZshからの出力は、>接頭辞のない行にあります。)

> url="https://github.com/gohugoio/hugo/releases/latest"
> latest=$(curl --silent --head "$url" | grep Location)
> tag=$(echo "$latest" | cut -d'/' -f8)
> version=$(echo "${tag//v}")
> echo "hugo_${version}_Linux-64bit.tar.gz"
_Linux-64bit.tar.gz 

期待した出力はhugo_0.65.3_Linux-64bit.tar.gzでしたが、引用符で囲まれた文字列を使用したechoの呼び出しの出力では、${version}に続くバイトが先頭のバイトを上書きするために使用されているようです引用された文字列。

ここでは、2つの異なる引用符付き文字列を使用して、何が起こっているのかを明確にします。

> echo "hugo_${version}test"
test_0.65.3
> echo "hugo_${version}lorem ipsum dolor sit amet"
lorem ipsum dolor sit amet

これを実行すると、同じnexpected結果が得られます。

> version=$(echo "${tag:1}")
> echo "hugo_${version}_Linux-64bit.tar.gz"
_Linux-64bit.tar.gz 

しかし、これを行うとexpectedの結果が得られます。

> version=0.65.3
hugo_0.65.3_Linux-64bit.tar.gz

この最後の結果が必要なものですが、もちろん、スクリプトが動的ではなく静的になるため、あまり役に立ちません。スクリプトで$versionの値をハードコーディングせずに、目的の結果を得るにはどうすればよいですか?

curlによって返される行は、改行で終了します。 (MS-dos行末)。改行はUnixツールによって削除されますが、最後に改行が残ります。

dos2unixを使用するようにこの行を修正します(そしてechoへの引数を引用符で囲み、 BashPitfalls#14 で説明されているバグを回避します):

version="$(echo "${tag//v}" | dos2unix)"

...または、シェルの組み込み構文を使用してboth変更を一度に実行します。

version=${tag//[$'v\r']/}

dos2unixは他の変更をいくつか行います(UNIXで必要なテキストの最後の行の後に末尾の改行を追加するなど)。ただし、このような1行の文字列ではそれらのどれも重要ではありません。

16
ctrl-alt-delor

ctrl-alt-deloranswer は、この動作が見られる理由を説明しています。ただし、根本的な目標に対処するには、「最新の」リダイレクトを解釈する代わりに、 GitHub API を使用することをお勧めします。

version=$(curl https://api.github.com/repos/gohugoio/hugo/releases/latest | jq -r '.tag_name | ltrimstr("v")')

これはAPIに最新のHugoリリースの情報を要求し、 jq を使用してタグ名を抽出し、先行する「v」を削除します。

理想的には、返されたJSONからアセット名とURLを抽出することもできます。

14
Stephen Kitt