360

名前に「Music」という単語が含まれるファイルとフォルダーを除いて、ディレクトリの内容をコピーしたいとします。

cp [exclude-matches] *Music* /target_directory

これを実現するには、[exclude-matches] の代わりに何を使用する必要がありますか?

4

11 に答える 11

408

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
于 2008-10-19T21:32:42.253 に答える
247

シェル オプションを使用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])
于 2008-10-20T00:15:43.097 に答える
26

(私が知っている)bashではありませんが、:

cp `ls | grep -v Music` /target_directory

これはまさにあなたが探していたものではないことはわかっていますが、あなたの例を解決します。

于 2008-10-19T21:23:42.913 に答える
10

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/
于 2008-10-19T21:40:26.780 に答える
6

非常に単純なforループを使用することもできます。

for f in `find . -not -name "*Music*"`
do
    cp $f /target/dir
done
于 2008-10-19T21:32:27.997 に答える
4

私の個人的な好みは、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
于 2011-02-18T09:35:26.347 に答える
3

これに対する 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 は、こ​​れを制御するのに役立ちます。

于 2008-10-19T21:23:13.473 に答える
3

*.txt次の作業は、番号で始まるものを除いて、現在のディレクトリ内のすべてのファイルを一覧表示します。

これは、、、bashおよびその他すべての POSIX 互換シェルで機能します。dashzsh

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. 1 行目では、このパターン/some/dir/*.txtにより、名前が でfor終わるすべてのファイルに対してループが繰り返されます。/some/dir.txt

  2. 2 行目では、不要なファイルを除外するために case ステートメントが使用されています。–${FILE##*/}式は、ファイル名 (ここでは ) から先頭の dir 名コンポーネントをすべて取り除き/some/dir/、パターンがファイルのベース名とのみ照合できるようにします。(サフィックスに基づいてファイル名のみを除外する場合は、$FILE代わりにこれを短縮できます。)

  3. case3 行目では、 pattern ) 行に一致するすべてのファイル[0-9]*がスキップされます (continueステートメントはforループの次の繰り返しにジャンプします)。– 必要に応じて、ここでさらに興味深いことを行うことができます。たとえば、 を使用して文字 (a–z) で始まらないすべてのファイルをスキップし[!a-z]*たり、複数のパターンを使用して複数の種類のファイル名[0-9]*|*.bakをスキップしたりできます (両方の.bakファイルをスキップするなど)。 、および数字で始まらないファイル。

于 2011-02-28T09:24:39.077 に答える
1

これにより、正確に「音楽」を除外します

cp -a ^'Music' /target

Music?* や *?Music などを除外するためのあれこれ

cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target
于 2011-02-12T18:06:50.543 に答える