フォルダを繰り返す場合
for f in $path
ワイルドカードに一致するファイルがないにもかかわらず、ループが入力され続ける予期しない動作が発生しました。私はcygwinを使っていますが、これは私のコードです
#!/bin/sh
here=$(pwd)
release(){
release="$1"
targetdisk="$2"
package="$3"
searchPath="../$package/${package}Setup/*/*/*.msi"
echo $searchPath
ls $searchPath
for f in $searchPath; do
mode=$(echo $file | sed -e 's:.*/.*/\(.*\)/.*\.msi:\1:')
version=$(echo $file | sed -e 's:.*/\(.*\)/.*/*.\.msi:\1:')
PREVIOUSIFS=$IFS
IFS=#
targetPath="$targetdisk:\\Software and tools\\Install\\$release"
newFile="$targetPath\\$package-$mode-$release.exe"
if [ ! -d "$targetPath" ]; then
mkdir -p "$targetPath"
fi
echo $newFile
echo $f
#cp $file $newFile
IFS=$PREVIOUSIFS
done;
}
release $1 $2 MyStuff
MyStuffをわざと入れたところ存在しません。
$ ./release.sh 1.0-dev G
../MyStuff/MyStuffSetup/*/*/*.msi
ls: ../MyStuff/MyStuffSetup/*/*/*.msi: No such file or directory
G:\Software and tools\Install\1.0-dev\MyStuff--1.0-dev.exe
../MyStuff/MyStuffSetup/*/*/*.msi
しかし、ご覧のとおり、両方のエコーが実行されます。一致するものがないのに、なぜこれが起こるのですか?
答え1
どのファイルとも一致しないワイルドカードパターンは拡張されません。その目的は、ワイルドカード文字を含むがパターンの一部ではないコマンドにパラメータを入力できるようにすることです。これは、コマンドラインで2つの引用符文字を時々保存できるため、ある程度意味があります。スクリプトでは、これは非常に迷惑なことです。残念ながら、レガシーshではこの動作を変更する方法はありません。パターンが拡張されていないことを確認できます。
for f in "../$package/${package}Setup"/*/*/*.msi; do
if [ "$f" = "../$package/${package}Setup"/*/*/*.msi" ]; then
# No match
break
fi
…
done
一致しないワイルドカードパターンを空のリストに拡張するようにBashに指示できます。 shebang行をに変更すると、次のことが#!/bin/bash
できます。
shopt -s nullglob
for f in "../$package/${package}Setup"/*/*/*.msi; do
…
スクリプトに他の問題があります。searchPath
にスペースやワイルドカード(バックスラッシュを含む)が含まれていると、変数の使用は中止されます$package
。変数の置換を引用符なしでそのままにしないでください$searchPath
。変数置換をスペースで区切られたパターンのリストとして扱う場合を除き、常に二重引用符を使用してください。しかし、ここではそうではありません。 $package
文字列(二重引用符が必要です)なので、*
バッチをワイルドカードパターンにすることは明らかです。上記のようにパターンをfor
ループに直接置きます。
ロギングの場合、これらのコマンドを使用する代わりにecho
(変数の置換に二重引用符がないため、パラメータが破損する可能性があります)、それを使用して実行されるとset -x
stderrに各コマンドを表示します。
スクリプトのある時点で設定していますが、IFS=#
決して分割しません#
。IFS
使用する予定がない場合は設定しないでください。
いくつかの質問がありますmode=$(echo $file | sed -e 's:.*/.*/\(.*\)/.*\.msi:\1:')
。上記のように二重引用符がありません"$file"
。また、各ファイルに対する追加の処理呼び出しがsed
遅く(Cygwinでの外部プロセスの実行が遅い)、複雑すぎます。シェルには文字列処理構造がありますが、ここでは十分です。あなたの
dir="${file%/*}"
mode="${dir##*/}"
dir="${dir%/*}"
version="${dir##*/}"
答え2
このスクリプトには多くの問題がありますが、あなたが尋ねる動作(ループの理由)は次のとおりです。
シェル構造から
for f in <expr>; do <commands>; done
ファイルパターンは通常「expr」に使用され、これはユーザーが実行するシェルファイル名のワイルドカードに置き換えられます。ただし、式が一致するものがないため、ワイルドカードは式をファイルパスのリストに拡張しません。ただし、他の多くの言語と同様に、長さゼロ(空白)のリストではなく、ループの上に表示されるアスタリスクを持つパス式です。したがって、ループは一度実行され、$ fは* .msiで終わる非拡張文字列と同じに設定されます。ループの前の位置をエコーすることでこれを確認できます。 lsと一緒に使用しているので、これがどんなものとも一致しないことを知っています。これが「該当するファイルやディレクトリがありません」というエラーが発生する理由です。
(また、ループで$ fileを使用したことに注意してください。私の考えでは、そこで$ fを使用しようとしていたようです。