次の例に示すように、変数で指定されたファイルを一覧表示できる必要があります。
X="myfile.txt"
$ ls ${X}
残念ながら、一部の人はファイル名にスペースを使用しているため、次のような場合があります。
X="my file.txt"
次の方法で解決できますls "${X}"
ただし、次のような場合でもこれが発生する可能性があります。
X="my file.*"
ワイルドカードは二重引用符内で拡張されないため、問題が発生します。
すべての状況に適用されるものはありますか?
編集する
X
次の配列で宣言されます。
X=("my file."*)
ls "$X[@]"
宣言するとワイルドカード文字が拡張されるため、十分ではありません。使用時に拡張する必要がありますls
。
答え1
強く打つ
では、bash
変数を引用解除することを分割+グローブ演算子と呼ぶこともあります。
分割部分は$IFS
特殊パラメータを使用して調整でき、グローバル部分はnoglob
次のオプションを使用して調整できます。
ワイルドカードの場合のみ$IFS
空の文字列に設定します。
file_pattern='foo bar *.txt'
IFS= # disable splitting
set +o noglob # make sure glob is enabled
ls -ld -- $file_pattern # split+glog with split disabled.
パターンがどのファイルとも一致しない場合は、ls
リテラル引数を受け取り、foo bar *.txt
ファイルが存在しないと文句を言います。
分割に対してのみ($PATH
ここではコロンで区切られた変数分割が例として使用されます)noglob
オプションを設定します。
IFS=: # split on :
set -o noglob
ls -ld -- $PATH # split+glob with glob disabled
空であるか設定されていない場合$var
、空であっても拡張時に引数は生成されず、空の引数が生成されます$IFS
。
$PATH
$PATH
空(unsetではない)$PATH
は、コマンドが現在の作業ディレクトリから取得され、ls
引数が渡されないときに現在の作業ディレクトリも一覧表示されることを意味するため、ここでは許可されます。
$PATH
現在の作業ディレクトリを意味する(たとえば)に空の要素がある場合、それについて不平を言う対応する空の引数が渡さ/bin::/usr/bin
れます。ls
1つの例外は、空の要素が最後の要素である場合(と同様/bin:/usr/bin:
)、最後の要素が削除されることです。
同様の変数を分割するより正しい方法は、次のものを$PATH
使用することです。
IFS=:
set -o noglob
printf '<%s>\n' $PATH''
この追加部分は、次の''
空の要素が除去されるのを防ぎ、空の要素が$PATH
まったく要素ではなく空の要素に分割されることを保証します。
扱いにくい
zshでは、引数の拡張中に分割とワイルドカードは暗黙的に実行されません。$=var
-$IFS
分割、${(s[separator])var}
区切り文字ベースの分割、$~var
ワイルドカード(または-分割とワイルドカードの$=~var
組み合わせ)$IFS
を使用して明示的に要求する必要があります。
だから:
file_pattern='foo bar *.txt'
ls -ld -- $~file_pattern
(パターンがどのファイルとも一致しない場合、コマンドはls
中断されます²)。
IFS=:
ls -ld -- $=PATH # preserves all empty elements even trailing ones
ls -ld -- ${(s[:])PATH} # split, discarding empty elements
ls -ld -- "${(@s[:])PATH}" # split, preserving empty elements
¹このオプションを有効にしない限り(管理対象以外のオプションセットではfailglob
)bashは中断されます(サブシェルを終了するか、サブシェルで実行されていない場合は読み取ったすべてのコードをスキップします)。または、このオプションを有効にすると、次に展開されます。この場合は何もないため、現在の作業ディレクトリが一覧表示されます。shopt
set
nullglob
shopt
ls
²zshで失敗したglobは構文エラーのように処理され、対応するシェルプロセスはエラーと失敗した終了状態で終了します(対話型シェルではデフォルトのシェルを終了せずにプロンプトに戻ります)。ここでは、外部コマンドと同様に、ls
これを実行するために生成されたサブプロセスのみが終了します。グローバル拡張がここで発生するためです。ls
たとえば、シェル関数で再定義すると、状況が異なります。
答え2
ワイルドカードを使用したい場合は、変数を使用することは複数のファイルと一致する可能性があるため、良い考えではありません。
解決策:配列を使用してください!
X=("my file."*)
ls "${X[@]}"
# or
for f in "${X[@]}"; do
some_command "$f"
done
値を割り当てるときは、引用符の*
外にする必要があります。
確認するここ変数拡張時のみグローバル拡張のためのソリューションです。