web-dev-qa-db-ja.com

パス名展開を使用して変数にファイル名を割り当てます

パス名の展開を利用して変数にファイル名を割り当てる信頼できる方法はありますか?

これは機能しますが、怪しげに見えます。

the_file="$(echo ~/downloads/stack-*-linux-x86_64-static.tar.gz)"

ファイルが存在する場合、その完全パスが$the_fileに割り当てられます。それ以外の場合は、偽のglobパターンが発生します。

6
undostres

グロッビングはリストコンテキストでのみ発生するため、array変数に割り当てる必要があります。 ksh93bashzshmkshまたはyashを使用:

the_files=(~/downloads/stack-*-linux-x86_64-static.tar.gz)

またはsh内:

set -- ~/downloads/stack-*-linux-x86_64-static.tar.gz

$1$2...に割り当てる.

そして最初の要素を取得するには:"${the_files[1]}" in zshまたはyash(または単に$the_files[1] in zsh)または"${the_files[0]}" in kshまたはbash

すべての要素:"${the_files[@]}"zsh内の$the_filesも)。

$IFSの最初の文字に結合された要素の連結については、"${the_files[*]}"(_zshを含む"$the_files"も)。または、zsh${(j:, :)the_files}の任意の文字列と結合します(ここでは,と結合します)。

もう少しメモ

スカラー変数への割り当て

the_file=~/downloads/stack-*-linux-x86_64-static.tar.gz

~は展開されますが、notグロブです。ただし、次のように変数を展開するときに引用符を使用するのを忘れた場合:

printf '%s\n' $the_file # instead of printf '%s\n' "$the_file"

次に、$the_fileのコンテンツはsplit + globの対象となり、その時点で展開されますこれにより、実際には機能しないと考えられますチルド拡張と組み合わせるとさらに面倒になります。

たとえば、$HOME/All * Users/meであり、$IFSがデフォルト値に設定されている場合、$the_fileには/All * Users/me/downloads/stack-*-linux-x86_64-static.tar.gzが含まれ、printf/Allに続いて現在のディレクトリ内のすべてのファイル名(*の展開)を出力します。 Users/me/downloads/stack-*-linux-x86_64-static.tar.gzの拡張。

パターンがどのファイルとも一致しない場合

zshではエラーが発生しますが、他のシェルではパターンは変更されません。ここでのベストは、パターンがまったく何にも拡張されないことです。

zshを使用すると、Nグロブ修飾子を使用できます。

the_files=(~/downloads/stack-*-linux-x86_64-static.tar.gz(N))

ksh93には、~(N)グロブ演算子を使用した同様の機能があります。

the_files=(~/downloads/~(N)stack-*-linux-x86_64-static.tar.gz)

他のシェルでは、いくつかのグローバルオプションをオンにする必要があります(bashshopt -s nullglobyashset -o nullglob)。

4