Yanıtlar:
Bash'de extglob
, bu seçeneği etkinleştirerek yapabilirsiniz (elbette hedef dizini ls
ile değiştirin cp
ve 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
?
extglob
Kabuk seçeneği size komut satırında daha güçlü desen eşleştirme verir.
İle shopt -s extglob
aç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 .c
veya .h
dosyalardaki 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])
.c
veya .h
dosyalardan 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 extglob
bir GLOBIGNORE
değ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 GLOBIGNORE
yapabilmek rm *techno*
.
Ayrıca oldukça basit bir for
dö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
bash
kullanabilirsiniz while IFS='' read -r filename
, ancak o zaman yeni satırlar hala bir sorun. Genel olarak ls
dosyaları 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
, find
veya grep
iki dosya setleri gibi listeleri ve tedavi etmektir "diff" onları kullanarak comm
:
comm -23 <(ls) <(ls *Music*)
comm
diff
fazladan sarsıntısı olmadığı için tercih edilir .
Bu döner set 1 tüm unsurları ls
olan, 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. ls
Geniş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, *.txt
bir sayıyla başlayanlar dışında geçerli dizindeki tüm dosyalar listelenir .
Bu çalışır bash
, dash
, zsh
ve 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
, for
döngünün /some/dir
adı 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, $FILE
bunun yerine kısaltabilirsiniz .)
Üçüncü satırda, case
kalıba uyan tüm dosyalar [0-9]*
) satırı atlanır ( continue
ifade, for
dö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]*|*.bak
dosyaları her iki .bak
dosyayı atlamak için ve bir sayıyla başlamayan dosyalar.
*.txt
yerine 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
cp
MacOS üzerindeki manuel sayfa bir sahiptir -a
seçeneği ama tamamen farklı bir şey yok. Hangi platform bunu destekliyor?
ls /dir/*/!(base*)