「*」ワイルドカード文字を使用すると、ファイル移動/コピー機能が一度に1つのファイルのみを移動するのはなぜですか?

「*」ワイルドカード文字を使用すると、ファイル移動/コピー機能が一度に1つのファイルのみを移動するのはなぜですか?
function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png

.pngすべてのファイルではなく、見つかった最初のファイルだけを移動します。

ワイルドカードに一致するすべてのファイルにこのコマンドを適用するにはどうすればよいですか?

ベストアンサー1

mv1 *.pngワイルドカードパターンは最初に*.pngファイル名のリストと一致するように拡張され、次にファイル名のリストが関数に渡されます。

次に、関数の内部では、最初の$1引数を関数に渡し、スペースを含む部分を分割し、ファイル名のリストと一致して、ワイルドカードを含むスペースで区切られた部分を1つ以上のファイル名と一致するように置き換えます。複雑に聞こえますか?はい。この動作は時々役に立ち、しばしば問題を引き起こします。この分割と一致の動作は$1二重引用符の外でのみ発生するため、修正は簡単です。二重引用符を使用してください。変数の置換には常に二重引用符を使用してください。そうしない妥当な理由がなければです。

たとえば、現在のディレクトリに2つのファイルが含まれていて、関数A* algorithm.pnggraph1.png最初の引数として渡さmv1 *.pngれ、2番目の引数に渡されます。その後、合計で割ります。パターンは一致しますが、ワイルドカード文字は含まれません。したがって、関数は、およびパラメータを使用して実行されます。その機能を修正するとA* algorithm.pnggraph1.png$1A*algorithm.pngA*A* algorithm.pngalgorithm.pngmv-nA* algorithm.pngalgorithm.pngtargetdir-v

function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}

これにより、最初のファイルが正しく移動されます。

扱うみんなパラメーターは、最初のパラメーターの代わりにすべてのパラメーターを処理するようにシェルに指示します。"$@"関数に渡された引数の完全なリストを表すために使用できます。

function mv1 { mv -n "$@" "targetdir" -v |wc -l ;}

これはほぼ正確ですが、引数はオプションとして扱われるため、-ファイル名が文字で始まっても失敗します。mv渡す--と、mv「これ以降はオプションはありません」と通知されます。これは、ほとんどのコマンドでサポートされている非常に一般的なルールです。

function mv1 { mv -n -v -- "$@" "targetdir" |wc -l ;}

残りの問題は、mv失敗するとパイプの左側にあるコマンドの終了ステータスが無視されるため、関数が成功ステータスを返すことです。 Bash(またはksh)ではset -o pipefail。このオプションを設定すると、同じシェルで実行されている他のコードが失敗する可能性があるため、関数でローカルに設定する必要があります。これはbash 4.4以降で可能です。

function mv1 {
  local -
  set -o pipefail
  mv -n -v -- "$@" "targetdir" | wc -l
}

以前のバージョンでは設定がpipefail脆弱であるため、PIPESTATUS明示的に確認するのが最善です。

function mv1 {
  mv -n -v -- "$@" "targetdir" | wc -l
  ((!${PIPESTATUS[0] && !${PIPESTATUS[1]}}))
}

おすすめ記事