function mv1 { mv -n "$1" "targetdir" -v |wc -l ;}
mv1 *.png
.png
すべてのファイルではなく、見つかった最初のファイルだけを移動します。
ワイルドカードに一致するすべてのファイルにこのコマンドを適用するにはどうすればよいですか?
答え1
mv1 *.png
ワイルドカードパターンは最初に*.png
ファイル名のリストと一致するように拡張され、次にファイル名のリストが関数に渡されます。
次に、関数の内部では、最初の$1
引数を関数に渡し、スペースを含む部分を分割し、ファイル名のリストと一致して、ワイルドカードを含むスペースで区切られた部分を1つ以上のファイル名と一致するように置き換えます。複雑に聞こえますか?はい。この動作は時々役に立ち、しばしば問題を引き起こします。この分割と一致の動作は$1
二重引用符の外でのみ発生するため、修正は簡単です。二重引用符を使用してください。変数の置換には常に二重引用符を使用してください。そうしない妥当な理由がなければです。
たとえば、現在のディレクトリに2つのファイルが含まれていて、関数A* algorithm.png
のgraph1.png
最初の引数として渡さmv1 *.png
れ、2番目の引数に渡されます。その後、合計で割ります。パターンは一致しますが、ワイルドカード文字は含まれません。したがって、関数は、およびパラメータを使用して実行されます。その機能を修正するとA* algorithm.png
graph1.png
$1
A*
algorithm.png
A*
A* algorithm.png
algorithm.png
mv
-n
A* algorithm.png
algorithm.png
targetdir
-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]}}))
}
答え2
$1
は関数の最初のパラメータです。ここに一致する最初のファイルがあります*.png
。私はこれが"$@"
あなたが代わりに使用したいと思います$1
。
答え3
を使用する必要がありますmv1 \*.png
。
関数と対話すると、Linux 端末はアスタリスクをコマンドに直接渡すのではなく、一致する最初の引数を選択してコマンドに渡します。
アスタリスクを直接通過するには、アスタリスクをバックスラッシュにエスケープする必要があります。