Bash ワイルドカードとパラメータの渡し

Bash ワイルドカードとパラメータの渡し

次の単純化されたbashスクリプトがあります。

#!/bin/bash

files=("$@")

if [ "X$files" = "X" ]; then
  files=$HOME/print/*.pdf;
fi

for file in "${files[@]}"; do
  ls "$file";
done

引数(ファイル名)を引数として渡すと、このスクリプトは正しいファイル名を印刷します。一方、パラメータを渡さないと、次のものが印刷されます。

/home/user/print/*.pdf: No such file or directory

この場合、ファイル名が拡張されない理由と回避策は何ですか?一般的な「files = $ *」よりも優先されることを読んだので、files=("$@")AND設定を使用したことに注意してください。"${files[@]}"

答え1

files次のように指定します。スカラー代わりに変数大量に変える

存在する

 files=$HOME/print/*.pdf

一部を割り当てていますひも/home/highsciguy/print/*.pdf$filesスカラー(文字列とも呼ばれる)変数と同じです。

使用:

files=(~/print/*.pdf)

または

files=("$HOME"/print/*.pdf)

代わりに。シェルはワイルドカードパターンをファイルパスリストに展開し、各ファイルパスを次に割り当てます。$files 大量に

glob の拡張は割り当て中に行われます。

非標準のsh機能を使用する必要はなく、shここではなくシステムで動作するように作成して使用できます。bash

#!/bin/sh -

[ "$#" -gt 0 ] || set -- ~/print/*.pdf

for file do
  ls -d -- "$file"
done

set"$@"割り当てられた位置パラメータの配列。

もう一つのアプローチは保存することです。ワイルドカードパターンスカラー変数から:

files=$HOME/print/*.pdf

$files そして、変数が拡張されたときにシェルにglobを拡張させます。

IFS= # disable word splitting
for file in $files; do ...

これには$files引用符がないため(通常は行わないでください)、拡張は単語の区切り(ここでは無効)とワイルドカード/ファイル名の生成の影響を受けます。

したがって、*.pdf 一致するファイルのリストが拡張されます。ただし、$HOMEワイルドカードを含めると拡張される可能性があるため、配列変数を使用することをお勧めします。

答え2

配列がない古いシェルで and then のようなfiles=$*ものを見たことがあります。files=~/print/*.pdfls $files

二重引用符で囲まれていない変数置換は、変数の値を一致するファイル名(存在する場合)で置き換えるスペースで区切られたシェルワイルドカードパターンのリストとして解釈されます。たとえば、afterはfiles=~/print/*.pdfパラメータなどのようにls $files拡張されます。この場合、この割り当てはスクリプトに渡された引数をスペースで連結してから再分割します。ls/home/highsciguy/print/bar.pdf/home/highsciguy/print/foo.pdffiles=$*ls $files

ファイル名にスペースまたはワイルドカードが含まれていると、これらの操作はすべて失敗するため、これを行わないでください。代わりに配列を使用してください。

files=("$@")
if ((${#files[@]} == 0)); then
  files=("$HOME"/print/*.pdf)
fi

気づく

  • すべての配列割り当てには、配列値を括弧で囲む必要がありますvar=(…)
  • 配列が空であることをテストするには、配列の長さを確認してください。インデックス0の要素が設定されていない配列、または空の文字列の場合は"$files"空です。 nullを許可するかどうかをテストするために使用されなくなった方法filesもあります。すべての最新のシェルはこれを正しく実装します。 bashでは。[ "X$foo" = "X" ]$foo[ -n "$foo" ][[ -n $foo ]]

配列をサポートしていないシェルには、実際には1つの配列(シェルの位置引数または現在の関数)しかあ​​りません。ここでは実際に配列は必要ありませんfiles。実際、位置パラメータを使用する方が簡単です。

#!/bin/sh
if [ "$#" -eq 0 ]; then
  set -- ~/print/*.pdf
fi
for file do …

関連情報