回答:
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
f
を除いて、で始まるすべてのものにどのように一致しfoo
ますか?
extglob
シェルのオプションを使用すると、コマンドラインでより強力なパターンマッチングを提供します。
でオンにしshopt -s extglob
、でオフにしshopt -u extglob
ます。
あなたの例では、最初は次のようにします:
$ shopt -s extglob
$ cp !(*Music*) /target_directory
フル利用可能extは終了グロブビング事業者は(からの抜粋ですman bash
):
組み込みのshoptを使用してextglobシェルオプションを有効にすると、いくつかの拡張パターンマッチング演算子が認識されます。パターンリストは、|で区切られた1つ以上のパターンのリストです。 複合パターンは、次のサブパターンの1つ以上を使用して形成できます。
- ?(pattern-list)
指定されたパターンの0回または1回の出現に一致- *(pattern-list)
指定されたパターンの0回以上の出現に一致- +(パターンリスト)
指定されたパターンの1回以上の出現に一致します- @(pattern-list)
指定されたパターンの1つに一致します- !(pattern-list)
指定されたパターンの1つ以外のすべてに一致します
したがって、たとえば、現在のディレクトリにある、.c
または.h
ファイルではないすべてのファイルを一覧表示する場合は、次のようにします。
$ ls -d !(*@(.c|.h))
もちろん、通常のシェルグロビングは機能するので、最後の例は次のように書くこともできます。
$ ls -d !(*.[ch])
.c
または.h
ファイルの1つがディレクトリである場合の@Koveras 。
D
ディレクトリに含まれている可能性のあるサブディレクトリの内容は表示しませんD
。
(私が知っている)bashではありませんが、:
cp `ls | grep -v Music` /target_directory
これはあなたが探していたものとは正確には違いますが、あなたの例を解決します。
bashでは、への代替shopt -s extglob
はGLOBIGNORE
変数です。良くはありませんが、覚えやすいです。
元のポスターが望んでいたものの例:
GLOBIGNORE="*techno*"; cp *Music* /only_good_music/
完了したら、ソースディレクトリでunset GLOBIGNORE
実行できるようにrm *techno*
します。
かなり単純なfor
ループを使用することもできます。
for f in `find . -not -name "*Music*"`
do
cp $f /target/dir
done
-maxdepth 1
非再帰的に使用しますか?
find
重要でないファイル名が見つかった場合、バッククォートで使用すると不快な方法で壊れます。
私の個人的な好みは、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
bash
使用できますwhile IFS='' read -r filename
が、改行はまだ問題です。一般に、ls
ファイルの列挙には使用しないことをお勧めします。のようなツールfind
がはるかに適しています。
for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
私が使用していないこと、まだここで見たことがないトリックextglob
、find
またはgrep
セットとして2つのファイルのリストを処理することで、「差分」彼らが使用してcomm
:
comm -23 <(ls) <(ls *Music*)
comm
diff
余分なくずがないので、より望ましいです。
これは、セット1のすべての要素を返しますls
が、セット2にも含まれていませんls *Music*
。これは、適切に機能するために両方のセットがソートされた順序であることが必要です。ls
とglob展開に問題はありませんが、のようなものを使用している場合はfind
、必ずを呼び出してくださいsort
。
comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)
潜在的に有用です。
comm -23 <(ls) exclude_these.list
このための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
Findにはかなりの数のオプションがあり、含めるものと除外するものをかなり具体的にすることができます。
編集:コメントのアダムは、これは再帰的であると述べました。オプションfindmindthおよびmaxdepthは、これを制御するのに役立ちます。
find -maxdepth 1 -not -name '*Music*'
次の作品は*.txt
、数字で始まるものを除いて、現在のディレクトリ内のすべてのファイルをリストします。
これはで動作しbash
、dash
、zsh
および他のすべてのPOSIX互換のシェル。
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##*/}
式は、ファイル名(ここでは/some/dir/
)から先頭のdir名コンポーネントを削除して、パターンがファイルのベース名のみと照合できるようにします。(サフィックスに基づいてファイル名のみを削除する場合は、$FILE
代わりにこれを短縮できます。)
3 行目では、case
パターン[0-9]*
)行に一致するすべてのファイルがスキップされます(continue
ステートメントはfor
ループの次の反復にジャンプします)。–ここでもっと面白いことをしたい場合は、たとえば、を使用して文字(a〜z)で始まらないすべてのファイル[!a-z]*
をスキップするか、複数のパターンを使用して複数の種類のファイル名[0-9]*|*.bak
をスキップするなど、.bak
ファイルを両方ともスキップすることができます。 、および番号で始まらないファイル。
*.txt
代わりに照合しました*
)。今修正されました。
これは正確に「音楽」を除いてそれを行います
cp -a ^'Music' /target
これと、ミュージックのようなものを除外するためのものですか?*または*?
cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target
cp
MacOS のマニュアルページには-a
オプションがありますが、まったく異なることを行います。どのプラットフォームがこれをサポートしていますか?
ls /dir/*/!(base*)