"Mv" nin bir dosya koleksiyonunu tek bir normal dosyaya taşımasını nasıl önleyebilirim?


17

Yaptığım aptalca bir hata yüzünden ses koleksiyonumun küçük bir bölümünü kaybettim. :-(
GLADLY Oldukça yeni bir yedeğim vardı, ama yine de rahatsız ediciydi.Senin dışında gerçekten, yaramazlık yapan diğer suçlu mv, aşağıdaki gibi görünecekti:

Ses dosyalarının belirli bir şeması vardı:

ARTIST - Some Title YY.mp3

YY2 basamaklı yıl belirtimi nerede .

mkdir 90<invisible control character>

(Şimdiye kadar, aslında görünmez olan bir üçüncü fazlalık karakter yazdığımı bilmiyordum ...!)
Hepsi bir dizinde olmak yerine, 1990'ların tüm müziklerinin tek bir dizinde olmasını istedim. Ben de şöyle yazdım:

find . -name '* 9?.mp3' -exec mv {} 90 \;

Ne olduğu hakkında fikir edinmek o kadar zor değil ha? : ->
(felaket) sonucu, '90 bir şey ' denilen boş bir dizin (bir şey "görünmez" kontrol karakteri) ve n kez yazılan '90' adlı tek bir dosyaydı .

TÜM DOSYALAR GİTMİŞTİR. : - (((açıkçası)

Keşke , hedef "dosya" imzasının (* NIX: Her şey bir dosyadır ) üzerine bir (örneğin ) ile başlayıp başlamadığını zamanında kontrolmv ederdi . Ve elbette, hedefin var olup olmadığı . Sadece yukarıda belirtilen senaryo, bir varyantı vardır unuttum için ilk dizindeki. (ama elbette, orada olduğunu varsaydınız ...)d------drwxr-xr-xmkdir

Başkent W ile başlayan evcil hayvan nefret işletim sistemimiz bile bunu yapıyor . İsterseniz , hedef türünü (dosya? Dizini?) Belirtmeniz bile istenir .

Bu nedenle, merak ediyorum * NIXers'ın mvsadece bu tür istenmeyen sürprizlerden kaçınmak için kendimize bir " scriptlet" yazmak zorunda olup olmadığımızı merak ediyorum .


2
Tüm dosyalar gitmedi. En azından biri .mp3adıyla orada olmalı 90, yedeklemeniz olmayan biri olabilir.
Anthon

2
Heh, alaycı bir mizah anlayışın var, seni deli ediyorsun! :-P Bu benim OP benim kalın baskı "tek bir dosya" olarak adlandırılan dosya oldu. :)
sözdizimi

2
mvburada sorun değil, teknik olarak, bir dizi dosyayı taşıdığınızı bilmiyor. mvHer dosya için bir kez çalıştırıyorsunuz . İşte böyle find -exec ;çalışır. Eğer kullanılmış olsaydı find -exec +(bazı yorumlar gibi) mv olur birden fazla argüman var en kısa sürede çığlık.
Etan Reisner

Her bir mvdosya için çalıştırma ilk bakışta biraz daha az düşünülmüş gibi görünse de, kaynak dosyalar çeşitli alt dizinler arasında dağıldıktan sonra (daha önce de söylediğim gibi) tek aklı başında çözüm olacaktır. Test durumumda, kaynak dosyaların hepsi tek bir dizinde olduğu, bunun gerçek test durumum olduğu anlamına gelmez . Aslında bu sadece bir basitleştirme, çünkü bunu daha sonra kendi başıma kolayca ayrıntılandırabilirim. Ayrıca, azaltılmış uzunlukları nedeniyle soruları okumak daha az zaman alır. :)
sözdizimi

Neden mvvarış yerinin var olmasını isteyesiniz ki? mv oldfile newfilebir dosyayı yeniden adlandırmanın yoludur ve newfilezaten var olup bir dizin olmasını beklemek saçmadır .
Barmar

Yanıtlar:


37

/Dosyaları bir dizine taşımak istiyorsanız, hedefe a ekleyebilirsiniz . Dizin mevcut değilse bir hata mesajı alırsınız:

mv somefile somedir/
mv: cannot move ‘somefile’ to ‘somedir/’: Not a directory

Dizin varsa, dosyayı bu dizine taşır.


4
Çok teşekkür ederim! O zaman gelecekteki hayat kurtarıcım bu olmalı. Sana borçlandım. (Bir not olarak, bir arkadaşım aynı hatayı birkaç yıl önce yapmıştı, bu yüzden yalnız olmadığımı hissediyorum.)
sentaksör

1
Ayrıca, belirli Kabukları kullanırken, dosya adlarını sizin için otomatik olarak tamamlamak için Sekme seçeneğiniz vardır. Dizin adını tam olarak hatırlayamıyorsam ve son zamanlarda yaptığınız gibi bir karışıklık istemiyorsanız, sadece bir veya iki karakter adı ve HIT TAB'ı yumruklayın . O zaman emin olabilirsiniz, çünkü bu otomatik tamamlama onu oraya koydu ....
Andyz Smith

@AndyzSmith Şey, işte bu. TAB'yi yalnızca karmaşık dizinler veya yollar için kullanmak , ancak 2 harfli olanlar için değil , benim alışkanlığım diyebilirsiniz . :) Ama düşünün ... belki de ikinci durumu da düşünmeliyim şu andan itibaren.
syntaxerror

20

GNU coreutils mvzaten bir dizine taşımak istediğinizi belirten bir seçeneğe sahiptir: -t/ --target-directory. Bu seçeneğin argümanı yoksa, mvtüm dosyalarınızı aynı dosya adına taşımak yerine şikayet eder.

Taşıyıcıyı şöyle yazardım:

find . -name '* 9?.mp3' -exec mv -t 90 {} +

Mümkün olduğunca çok sayıda dosya adını birlikte kullanmak +yerine, \;daha hızlı yürütme ile sonuçlandığına dikkat edin.


Teşekkürler. (Yine de bu GNU-
izmlerinden

2
@sözdizimi hatası. Bu bir GNUizmdir. POSIXly:find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
Stéphane Chazelas

Bu en SNEAKY tek astar için çok teşekkür ederim! Sana verdiđim bir +5 olduđunu düţün. :) Gereksiz deneme-yanılma girişimleri yapacaktır .--- Ve bu açıklamayı neden yaptığımı çok iyi biliyorsunuz. Sadece POSIX (çok nadiren gerçekleşmez) olan bir makinede olmanız gerekiyor ve bir sonraki problemim burada olacak. :)
sözdizimi

1
@syntaxerror Bu yanıt sorununuzu çözüyorsa, lütfen bir dakikanızı ayırın ve soldaki oy sayımının altındaki onay işaretini tıklayın, bu sorununuzu herkesin çözdüğünü ve sitede teşekkür etmenin yolunu gösterir. Diğer cevaplanmış sorularınızdan sadece birkaçının cevapları kabul ettiğini gördüm, bunları da yeniden değerlendirmek isteyebilirsiniz.
Anthon

Hayır, sadece amaç. Bir cevabı kabul edene kadar sık ​​sık birkaç hafta, bazen 2 ay beklerdim. Bunun nedeni, bazı çok bilgili kişilerin ÇOK yüklü bir programa sahip olmaları ve yalnızca (genellikle en iyi) cevaplarını birkaç hafta sonra vermek için zaman bulabilmeleridir. Bu yüzden her zaman beklemelerini saygılı buluyorum. Ve eğer gerçekten yapmazlarsa, kesinlikle onay işaretine basmaktan çekinmeyeceğim. Ayrıca, bazı insanların neden SE + lezzetleri için her zaman bu kadar acele ettiğini anlamıyorum. Kolay, dostlar. Silahı atlama. :) Patronun sana baskı yapmıyor.
sentaksör

10

Buna ek olarak, gelecekte yanlışlıkla üzerine yazma işlemlerinden kaçınmayı planlıyorsanız, bunun için bir -iseçenek vardır mv. Şahsen herhangi bir dezavantaj düşünemiyorum

alias mv='mv -i'

Daha sonra bir şeyin üzerine yazmanız gerekirse, seçeneği geçmeniz yeterlidir -f.

Takma adlar, komutu doğrudan etkileşimli bir kabuğa yazarsanız etkili olurlar, tarafından çağrılma gibi durumlar için değil find. Koşabilirdin

find . -name '* 9?.mp3' -exec mv -i {} 90 \;

ve sonra mvvarolan bir dosyanın üzerine yazmaya çalışsaydınız size sorulurdu.


4
Veya - muhtemelen bilmediğiniz gibi - yerine ´ \ mv `yazın mv. Bu daha az bilinen "hile" değerin başına ters eğik çizgi ile komut görmezden neden olacak herhangi ad tanımları.
syntaxerror

Tabii ki, gerçekten konuşuyorsanız find ... -exec mv ..., o zaman ~/bin/mv(veya başka bir uygun dizin) oluşturmanız ve yapmanız gerekir /bin/mv -i "$@"- çünküfind ... -exec takma adlara bakmaz.
G-Man,

Bu durumda tercih ederim env mv. Daha az yazım. :) Yerel klavye düzenim, eğik çizgi için SHIFT tuşuna basılmasını gerektirdiğinden, (varsa) her zaman "eğik çizgi" sürümlerini tercih ederim.
sentaksör

1
@syntaxerror: BTW, yoruma (yeni bir yorumda) yanıt verdiğinizde, “@ G-Man” 'da olduğu gibi yazarın adından önce “@” harfinden bahsetmek gelenekseldir. Bu şekilde bilgilendiriliyorum. (Jenny D'nin yorumundan haberdar olduğum için son yorumunuza yarı zamanlı olarak yanıt verebildim.) Bir adın tamamını (boşluklar olmadan) kısaltabilir veya kullanabilirsiniz, örneğin, “@ StéphaneChazelas”. Bir yazının yazarı, o yazının yorumlarına otomatik olarak bildirilir. Bu yardım sayfasının Yorumlar bölümünde yanıtlama paragraflarına bakın .
G-Man,

1
Üzgünüm, bir gün internetsizdim. @ G-Man mvBaşlangıçta bir yerde kişisel bir versiyona sahip olmanın $PATHdaha temiz bir çözüm olacağını kabul ediyorum. Öte yandan öncelikle mvetkileşimli kabukta dikkatsizce olurum (çünkü hızlı olur). findBir fordöngü gibi daha karmaşık bir şey oluşturduğum ya da bir kabuk komut dosyası oluşturduğum anda, bir şey kırmamamı sağlamak için bazı kuru çalışma (kullanma echo) eğilimindeyim . Bu durumlarda el ele tutuşmaya ihtiyacım yok mv, çünkü zaten bazı düşünceler koyuyorum.
ayekat

7

Yukarıdaki mükemmel yanıtlara ek olarak, dosyaları taşıyıp taşımama konusunda neden soru alamadığınızı açıklığa kavuşturmak istiyorum.

Eğer taşırsanız biri yeni bir isme dosyası ve bu ismi bir dizin değil, mvyeni adıyla dosyanızı yeniden adlandırır.

Buradaki sorun , tüm dosyalar için bir kez değil, dosya başına bir kez findyürütmek için kullanmanızdır .mv

, Bunun yerine, yapmış olsaydım mv *90.mp3 90, o zaman mv"hedef dosya bir dizin olmadığını" hata iletisiyle başarısız olurdu.

Başka bir tavsiye, hedef yolu yazarken sekme tamamlamayı kullanmaktır. /Hedef adına ekleyerek size hedefin bir dizin olup olmadığını gösterecektir . mv -iVarolan bir dosyanın üzerine yazmak isteyip istemediğinizi de sormak için kullanabilirsiniz .


Bunun yerine, yapmış mv *90.mp3 90olsaydınız, mv "hedef dosya bir dizin değil" hata mesajıyla başarısız olur. Hah, evet, neden bu kadar karmaşık ha? Hattını kullanıyorum ve mutlu olacağım. Ancak bu önemsiz durumda. :) Çünkü sorularımı sormanın normal yolu bu: Basitlik uğruna onları daraltırdım. findŞimdiye kadar, 90'ların dosyalarının da "yakalamak" istediğim çeşitli alt dizinlere dağılabileceğini düşünen hiç kimse itiraz etmedi . Eğer ve sadece onlar eğer hep bir kaynak dizininde, sizin mvçizgi uygulanabilir.
sözdizimi

@syntaxerror Çok doğru - Bunu mv, araç seçiminizin bir eleştirisi olarak değil , nasıl davrandığının bir örneği olarak kastetmiştim .
Jenny D

1
Muhtemelen birleştirici bir şey inşa edebilirsiniz findve mvörneğin find /music -type d -exec mv {}/*90.mp3 targetdir\;- ama şimdi biraz karmaşık olduğumu hissediyorum ve sadece -iveya -tdaha verimli kullanıyorum
Jenny D

1
@Jenny: Örneğiniz find . -type d -exec mv {}/*9?.mp3 target \;işe yararsa , mvkomutun mv file targetyalnızca bir *9?.mp3dosya içeren her dizin için görünme riski vardır ; böylece tüm bu dosyalar (sonuncusu hariç) kaybolacaktır.
G-Man,

4
@syntaxerror: Sorununuzun ortaya çıktığı 42.000 satır komut dizisinin tamamı yerine, önemli bir bölümünü ortaya çıkarma çabasını alkışlarım. Ama verdin bile herkese bir şeyler yapmak istiyorum *.mp3bir dizin ağacı dosyaların, sen verebilir shopt -s globstarve daha sonra komutunu çalıştırın **/*.mp3- **Bir gibi hareket edecektir find.
G-Man,

1

Alternatif bir genel amaçlı strateji olarak, bu tür bir işlemin geçici bir komut dosyasına dönüştürülmesini öneririm. Ben yürütmeden önce ne yaptığımı anladığımdan emin olarak sonuçlarına bakmayı findve bunları mvelle bir komuta dönüştürmeyi tercih ederim . Örneğin.

find . -name '* 9?.mp3' > tmp
vim tmp

Şimdi bir dosya adları listesine bakabilir ve dosya içeriğini kabuk komutu olarak yeniden yazabilirim.

  • Dosya içeriğini bir satıra yerleştirin: ggVGJ
  • başına ekle: Imv [esc]
  • ekleme: Asomedir/ [esc]
  • Dosya 'yı kaydet. Tekrar oku. Nefes al.
  • source tmpKomut satırında yürütün .

Bu muhafazakar bir stratejidir, ancak yanlış yazılmış tarafından sık sık ısırıldım -exec veya sedkomutlar veya yanlış kabuk açılımları ve ben yavaş tutarlı bir yaklaşım alarak tercih ediyoruz.

Başka bir deyişle: Kullanmak için çok korkakım -exec.


1
Dışarı sol :%s/.*/"&"/bu durumda, bunu biliyorsun, çünkü - adımını her dosya en azından bir boşluk içeriyor.
G-Man,

1
Dosya adları boşluk veya başka özel karakterler içeriyorsa bu sizi ısıracaktır. Onları düzgün bir şekilde alıntılamanız gerekir. Bir komut listesinin gözden geçirilmesi özellikle hata yakalayamaz. Komutları çalıştırmadan önce gözden geçirmek echo mvyerine çalıştırmak mvve sonra echomutlu olup olmadığınızı kaldırmak gibi çok daha iyi yollar vardır .
Gilles 'SO- kötü olmayı bırak'

Boşluklu dosya adları gibi bir hatayı tespit etmek, bu tekniğin yardımcı olacağı şeydir :-)
Tom Rees

0

Başka seçenek:

-n, --no-clobber varolan bir dosyanın üzerine yazma

-i ile aynı, ama sormayacak, başarısız olacak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.