Yanıtlar:
Bash'de extglob, bu seçeneği etkinleştirerek yapabilirsiniz (elbette hedef dizini lsile değiştirin cpve ekleyin)
~/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
Daha sonra extglob'u şununla devre dışı bırakabilirsiniz:
shopt -u extglob
f, dışındaki her şeyle nasıl eşleşirsiniz foo?
extglobKabuk seçeneği size komut satırında daha güçlü desen eşleştirme verir.
İle shopt -s extglobaçarsınız ve ile kapatırsınız shopt -u extglob.
Örneğinizde, başlangıçta şunları yaparsınız:
$ shopt -s extglob
$ cp !(*Music*) /target_directory
Mevcut tüm dahili uçlu glob bing operatörleri (alıntı man bash):
Extglob kabuk seçeneği shopt yerleşik kullanılarak etkinleştirilirse, birkaç genişletilmiş desen eşleştirme operatörü tanınır. Bir desen listesi, | ile ayrılmış bir veya daha fazla desenin listesidir. Kompozit desenler, aşağıdaki alt şablonlardan biri veya daha fazlası kullanılarak oluşturulabilir:
- ? (kalıp listesi)
Verilen kalıpların sıfır veya bir tekrarıyla eşleşir- * (desen listesi)
Verilen desenlerin sıfır veya daha fazla örneğiyle eşleşir- + (desen listesi)
Verilen desenlerin bir veya daha fazla örneğiyle eşleşir- @ (desen listesi)
Belirtilen modellerden biriyle eşleşir- ! (kalıp listesi)
Verilen kalıplardan biri dışındaki herhangi bir şeyle eşleşir
Örneğin, geçerli dizindeki olmayan .cveya .hdosyalardaki tüm dosyaları listelemek isterseniz, şunları yaparsınız:
$ ls -d !(*@(.c|.h))
Tabii ki, normal kabuk globing işe yarıyor, bu nedenle son örnek de şöyle yazılabilir:
$ ls -d !(*.[ch])
.cveya .hdosyalardan birinin bir dizin olduğu durumda.
D, ancak dizinde bulunabilecek alt dizinlerin içeriğini listelemez D.
Bash değil (bildiğim), ama:
cp `ls | grep -v Music` /target_directory
Bunun tam olarak aradığınız şey olmadığını biliyorum, ancak örneğinizi çözecek.
Exec komutunu kullanarak mem maliyetinden kaçınmak istiyorsanız, xargs ile daha iyisini yapabileceğinize inanıyorum. Bence aşağıdakiler daha etkili bir alternatif
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/
Bash olarak, alternatif shopt -s extglobbir GLOBIGNOREdeğişken . Gerçekten daha iyi değil ama hatırlamayı daha kolay buluyorum.
Orijinal posterin istediği bir örnek olabilir:
GLOBIGNORE="*techno*"; cp *Music* /only_good_music/
Bittiğinde , kaynak dizinde unset GLOBIGNOREyapabilmek rm *techno*.
Ayrıca oldukça basit bir fordöngü de kullanabilirsiniz :
for f in `find . -not -name "*Music*"`
do
cp $f /target/dir
done
-maxdepth 1özyinelemesiz için kullanın ?
findÖnemsiz dosya adları bulursa, geri tıklamayla kullanmak hoş olmayan yollarla bozulur.
Kişisel tercihim grep ve while komutunu kullanmak. Bu, güçlü ve okunabilir komut dosyaları yazabilmenizi sağlar ve böylece tam olarak ne istediğinizi yaparsınız. Ayrıca bir yankı komutu kullanarak gerçek işlemi gerçekleştirmeden önce kuru bir çalışma gerçekleştirebilirsiniz. Örneğin:
ls | grep -v "Music" | while read filename
do
echo $filename
done
kopyalayacağınız dosyaları yazdırır. Liste doğruysa, bir sonraki adım echo komutunu aşağıdaki gibi copy komutuyla değiştirmektir:
ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done
bashkullanabilirsiniz while IFS='' read -r filename, ancak o zaman yeni satırlar hala bir sorun. Genel olarak lsdosyaları numaralandırmak için kullanmamak en iyisidir ; gibi araçlar findçok daha uygundur.
for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
Ben kullanmayan henüz burada görmedim Bir hile extglob, findveya grepiki dosya setleri gibi listeleri ve tedavi etmektir "diff" onları kullanarak comm:
comm -23 <(ls) <(ls *Music*)
commdifffazladan sarsıntısı olmadığı için tercih edilir .
Bu döner set 1 tüm unsurları lsolan, olmayan set 2'de de ls *Music*. Bu, düzgün çalışabilmesi için her iki kümenin de sıralanmış sırada olmasını gerektirir. lsGenişletme için sorun değil, ancak böyle bir şey kullanıyorsanız find, çağırdığınızdan emin olun sort.
comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)
Potansiyel olarak yararlı.
comm -23 <(ls) exclude_these.list
Bunun için bir çözüm find ile bulunabilir.
$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt
Bulun birkaç seçeneği vardır, neleri eklediğiniz ve hariç tuttuğunuz konusunda oldukça spesifik olabilirsiniz.
Edit: Adam yorumlarda bunun özyinelemeli olduğunu kaydetti. mindepth ve maxdepth seçeneklerini bulma bunu kontrol etmede yararlı olabilir.
find -maxdepth 1 -not -name '*Music*'/ target_directory
Aşağıdaki çalışmalarda, *.txtbir sayıyla başlayanlar dışında geçerli dizindeki tüm dosyalar listelenir .
Bu çalışır bash, dash, zshve diğer tüm POSIX uyumlu kabuklar.
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
Birinci satırda desen /some/dir/*.txt, fordöngünün /some/diradı biten tüm dosyalar üzerinde yinelenmesine neden olur .txt.
İkinci satırda, istenmeyen dosyaları ayıklamak için bir vaka ifadesi kullanılır. - ${FILE##*/}İfade, dosya adındaki (burada /some/dir/) önde gelen dir adı bileşenlerini kaldırır, böylece patters yalnızca dosyanın adıyla eşleşebilir. (Dosya adlarını yalnızca soneklere göre ayıklıyoruz, $FILEbunun yerine kısaltabilirsiniz .)
Üçüncü satırda, casekalıba uyan tüm dosyalar [0-9]*) satırı atlanır ( continueifade, fordöngünün bir sonraki yinelemesine atlar ). - İsterseniz burada daha ilginç bir şey yapabilirsiniz, örneğin kullanarak bir harfle (a – z) başlamayan tüm dosyaları atlamak gibi veya birkaç dosya adını [!a-z]*atlamak için birden fazla desen kullanabilirsiniz, örneğin [0-9]*|*.bakdosyaları her iki .bakdosyayı atlamak için ve bir sayıyla başlamayan dosyalar.
*.txtyerine sadece karşı eşleşen) bir hata vardı *. Şimdi düzeltildi.
bu tam olarak 'Müzik' hariç
cp -a ^'Music' /target
Bu ve Müzik? * veya *? Müzik gibi şeyleri hariç tutmak için
cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target
cpMacOS üzerindeki manuel sayfa bir sahiptir -aseçeneği ama tamamen farklı bir şey yok. Hangi platform bunu destekliyor?
ls /dir/*/!(base*)