名前に「Music」という単語が含まれるファイルとフォルダーを除いて、ディレクトリの内容をコピーしたいとします。
cp [exclude-matches] *Music* /target_directory
これを実現するには、[exclude-matches] の代わりに何を使用する必要がありますか?
名前に「Music」という単語が含まれるファイルとフォルダーを除いて、ディレクトリの内容をコピーしたいとします。
cp [exclude-matches] *Music* /target_directory
これを実現するには、[exclude-matches] の代わりに何を使用する必要がありますか?
Bashでは、このようにオプションを有効にすることでそれを行うことができます(もちろん、ターゲットディレクトリをextglob
置き換えls
て追加します)cp
~/foobar> shopt extglob
extglob off
~/foobar> ls
abar afoo bbar bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob # Enables extglob
~/foobar> ls !(b*)
abar afoo
~/foobar> ls !(a*)
bbar bfoo
~/foobar> ls !(*foo)
abar bbar
後でextglobを無効にすることができます
shopt -u extglob
シェル オプションを使用extglob
すると、コマンド ラインでより強力なパターン マッチングを実行できます。
でオンにしshopt -s extglob
、 でオフにしshopt -u extglob
ます。
あなたの例では、最初に次のことを行います。
$ shopt -s extglob
$ cp !(*Music*) /target_directory
使用可能な完全な拡張グロビング演算子は次のとおりです(からの抜粋):man bash
shopt ビルトインを使用して extglob シェル オプションを有効にすると、いくつかの拡張パターン マッチング演算子が認識されます。pattern-list は、| で区切られた 1 つ以上のパターンのリストです。 複合パターンは、次のサブパターンの 1 つまたは複数を使用して形成できます。
- ?(pattern-list)
指定されたパターンの 0 回または 1 回の出現に一致します- *(pattern-list)
指定されたパターンの 0 回以上の出現に一致します- +(pattern-list)
指定されたパターンの 1 つ以上の出現に一致します- @(pattern-list)
指定されたパターンの 1 つに一致します- !(pattern-list)
指定されたパターンの 1 つを除くすべてに一致します
したがって、たとえば、現在のディレクトリにあるファイルのうち、.c
または.h
ファイル以外のすべてのファイルを一覧表示する場合は、次のようにします。
$ ls -d !(*@(.c|.h))
もちろん、通常のシェル グロービングは機能するため、最後の例は次のように書くこともできます。
$ ls -d !(*.[ch])
(私が知っている)bashではありませんが、:
cp `ls | grep -v Music` /target_directory
これはまさにあなたが探していたものではないことはわかっていますが、あなたの例を解決します。
exec コマンドを使用することによるメモリ コストを回避したい場合は、xargs を使用したほうがよいと思います。以下はより効率的な代替手段だと思います
find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec
find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/
非常に単純なfor
ループを使用することもできます。
for f in `find . -not -name "*Music*"`
do
cp $f /target/dir
done
私の個人的な好みは、grep と while コマンドを使用することです。これにより、強力でありながら読みやすいスクリプトを記述して、最終的に必要なことを正確に行うことができます。さらに、echo コマンドを使用すると、実際の操作を実行する前に予行演習を実行できます。例えば:
ls | grep -v "Music" | while read filename
do
echo $filename
done
コピーすることになるファイルを印刷します。リストが正しい場合、次のステップは、次のように echo コマンドを copy コマンドに置き換えるだけです。
ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done
これに対する 1 つの解決策は、find で見つけることができます。
$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt
検索にはかなりの数のオプションがあり、含めるものと除外するものをかなり具体的にすることができます。
編集: コメントの Adam は、これは再帰的であると指摘しました。find オプションの mindepth と maxdepth は、これを制御するのに役立ちます。
*.txt
次の作業は、番号で始まるものを除いて、現在のディレクトリ内のすべてのファイルを一覧表示します。
これは、、、bash
およびその他すべての POSIX 互換シェルで機能します。dash
zsh
for FILE in /some/dir/*.txt; do # for each *.txt file
case "${FILE##*/}" in # if file basename...
[0-9]*) continue ;; # starts with digit: skip
esac
## otherwise, do stuff with $FILE here
done
1 行目では、このパターン/some/dir/*.txt
により、名前が でfor
終わるすべてのファイルに対してループが繰り返されます。/some/dir
.txt
2 行目では、不要なファイルを除外するために case ステートメントが使用されています。–${FILE##*/}
式は、ファイル名 (ここでは ) から先頭の dir 名コンポーネントをすべて取り除き/some/dir/
、パターンがファイルのベース名とのみ照合できるようにします。(サフィックスに基づいてファイル名のみを除外する場合は、$FILE
代わりにこれを短縮できます。)
case
3 行目では、 pattern ) 行に一致するすべてのファイル[0-9]*
がスキップされます (continue
ステートメントはfor
ループの次の繰り返しにジャンプします)。– 必要に応じて、ここでさらに興味深いことを行うことができます。たとえば、 を使用して文字 (a–z) で始まらないすべてのファイルをスキップし[!a-z]*
たり、複数のパターンを使用して複数の種類のファイル名[0-9]*|*.bak
をスキップしたりできます (両方の.bak
ファイルをスキップするなど)。 、および数字で始まらないファイル。
これにより、正確に「音楽」を除外します
cp -a ^'Music' /target
Music?* や *?Music などを除外するためのあれこれ
cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target