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