-Exec mv {} ./target/ + bulmak neden çalışmıyor?


98

Tam olarak ne olduğunu öğrenmek istiyorum {} \;ve {} \+ve | xargs ...yapmak. Lütfen bunları açıklamalarla netleştirin.

3 komutun altında aynı sonucu çalıştırır ve verir, ancak ilk komut biraz zaman alır ve format da biraz farklıdır.

find . -type f -exec file {} \;
find . -type f -exec file {} \+
find . -type f | xargs file

Bunun nedeni, birinci filekomuttan gelen her dosya için findkomutu çalıştırmasıdır. Yani, temelde şu şekilde çalışır:

file file1.txt
file file2.txt

Ancak son 2, -execaşağıdaki gibi tüm dosyalar için dosya komutunu bir kez çalıştır komutlarıyla bulun :

file file1.txt file2.txt

Daha sonra birincisinin sorunsuz çalıştığı ancak ikincisinin hata mesajı verdiği aşağıdaki komutları çalıştırıyorum.

find . -type f -iname '*.cpp' -exec mv {} ./test/ \;
find . -type f -iname '*.cpp' -exec mv {} ./test/ \+ #gives error:find: missing argument to `-exec'

İle komut için {} \+bana hata mesajı veriyor

find: missing argument to `-exec'

Neden? kimse neyi yanlış yaptığımı açıklayabilir mi?


gerçek soru basit, neden birincisi çalışıyor ve ikincisi çalışmıyor? (1) bul. -tip f -iname ' .cpp' -exec mv {} ./test/ \; (2) bul. -type f -iname ' .cpp' -exec mv {} ./test/ \ +
Hossain

Yanıtlar:


185

Manuel sayfa (veya çevrimiçi GNU manuel ) hemen hemen herşeyi açıklıyor.

bul -exec komutu {} \;

Her sonuç command {}için yürütülür. Tüm geçtiği {}yerleri dosya adı ile değiştirilir. ;, kabuğun onu yorumlamasını önlemek için bir eğik çizgi ile başlar.

bul -exec komutu {} +

Her sonuç commanddaha sonra eklenir ve yürütülür. Komut uzunluğu sınırlamalarını hesaba katarsak, bu komutun beni destekleyen kılavuz sayfasıyla daha fazla kez çalıştırılabileceğini tahmin ediyorum:

komutun toplam çağrı sayısı, eşleşen dosyaların sayısından çok daha az olacaktır.

Kılavuz sayfasındaki bu alıntıya dikkat edin:

Komut satırı, xargs'ın komut satırlarını oluşturduğu şekilde oluşturulmuştur.

Bu nedenle boşluklar arasında {}ve +dışında hiçbir karaktere izin verilmez . +argümanların aynı komuta eklenmesi gerektiğini algılamasını sağlar xargs.

Çözüm

Neyse ki GNU gerçeklemesi mv, hedef dizini bir -tveya daha uzun parametreli bir argüman olarak kabul edebilir --target. Kullanım şu şekilde olacaktır:

mv -t target file1 file2 ...

Sizin findkomut haline gelir:

find . -type f -iname '*.cpp' -exec mv -t ./test/ {} \+

Kılavuz sayfasından:

-exec komutu;

Komutu çalıştır; 0 durumu döndürülürse true. Aşağıdaki tüm argümanlar, aşağıdakilerden oluşan bir argüman olana kadar komutun argümanları olarak alınır. karşılaşılır. `{} 'Dizesi, find'ın bazı sürümlerinde olduğu gibi, yalnızca bağımsız değişkenlerde değil, komutun bağımsız değişkenlerinde bulunduğu her yerde işlenen geçerli dosya adı ile değiştirilir. Bu yapıların her ikisinin de kabuk tarafından genişlemesini önlemek için kaçılması (bir `` ile) veya alıntı yapılması gerekebilir. -Exec seçeneğinin kullanımına ilişkin örnekler için ÖRNEKLER bölümüne bakın. Belirtilen komut her eşleşen dosya için bir kez çalıştırılır. Komut, başlangıç ​​dizininde yürütülür. -Exec eyleminin kullanımıyla ilgili kaçınılmaz güvenlik sorunları vardır; bunun yerine -execdir seçeneğini kullanmalısınız.

-exec komutu {} +

-Exec eyleminin bu varyantı, seçilen dosyalarda belirtilen komutu çalıştırır, ancak komut satırı, seçilen her dosya adını sonuna eklenerek oluşturulur; komutun toplam çağrı sayısı, eşleşen dosyaların sayısından çok daha az olacaktır. Komut satırı, xargs'ın komut satırlarını oluşturduğu şekilde oluşturulmuştur. Komut içinde yalnızca bir `` {} '' örneğine izin verilir. Komut, başlangıç ​​dizininde yürütülür.


1
Aslında nasıl çalıştığını biliyorum, bu kılavuzu birkaç kez inceledim, ancak {} + kullanmakla ilgili bir hata mesajı aldım, ancak {} için çalışıyor \; ve Windows'ta Cygwin kullanıyorum.
Shahadat Hossain

1
@Shahadat: "Kılavuz sayfasından" önceki bölümü okudunuz mu? Sen koyduk ./test/arasında {}ve +fakat hiçbir boşluk olmayan karakterleri bu arasına girebilir.
Lekensteyn

ru ./test/ öğesini {} ve + arasına koymamam gerektiğini söyleyerek. O zaman mv komutu nasıl çalışacak; mv, {} olan kaynağa ve ./test/ olan hedefe ve + ile sonlandırmaya ihtiyaç duyar. Lütfen doğru düşündüğünüz komutu yazabilir misiniz?
Shahadat Hossain

@Shahadat: Neyi başarmaya çalıştığını anlıyorum. Windows programları yürütürken yavaştır, bu nedenle onu tek bir komutla birleştirmek istersiniz. Cevaba bir alternatif ekleyeceğim.
Lekensteyn

1
+O "uç" taki dosyaları yapışır (ve yerine beri komut biraz garip AFAIU olduğu {}yani neden kullanılarak) {}bu kafa karıştırıcı - hiç. -tBilmediğim seçenek için teşekkürler, bu seçeneğin bu -exec +soruna geçici bir çözüm olarak yaratıldığı anlaşılıyor !
e2-e4

6

ZSH kabuğu kullanarak Mac OSX'te de aynı sorunla karşılaştım : bu durumda için seçenek yok , bu yüzden başka bir çözüm bulmam gerekiyordu. Ancak aşağıdaki komut başarılı oldu:-tmv

find .* * -maxdepth 0 -not -path '.git' -not -path '.backup' -exec mv '{}' .backup \;

İşin sırrı parantezlerden alıntı yapmaktı . execKomutun sonunda parantez olmasına gerek yoktur .

Ubuntu 14.04 ( BASH ve ZSH kabukları ile) altında test ettim , aynı şekilde çalışıyor.

Ancak, +işareti kullanırken, gerçekten de execkomutun sonunda olması gerektiği anlaşılıyor .


{}ihtiyaçlar alıntı edilecek fishve rckabukları, ancak içinde zsh, bashne de Bourne veya csh ailelerin başka kabuklarla.
Stephane Chazelas

@StephaneChazelas Yep, bir Ubuntu altında tekrar test edildi bash, gerçekten de alıntılar gerekli değil. Merakla, MacOS altında (kullanarak zsh) alıntı yapmama konusunda bir sorun yaşadım . Ama tekrar denemek için ulaşabileceğim bir
Mac'im yok

3

Standart eşdeğer find -iname ... -exec mv -t dest {} +için finddesteklemeyen uygulamalar -inameya da mvdestek yok uygulamaları -tbağımsız değişken yeniden vermek bir kabuk kullanmaktır:

find . -name '*.[cC][pP][pP]' -type f -exec sh -c '
  exec mv "$@" /dest/dir/' sh {} +

Kullanarak -name '*.[cC][pP][pP]', cveya öğesinin büyük harf sürümünün ne olduğuna karar vermek için mevcut yerel ayara güvenmekten de kaçınıyoruz p.

Bunun herhangi bir kabukta özel olmadığına dikkat edin +, ;bu yüzden alıntı yapılmasına gerek yoktur (yine de, bu tür kabukların bir alıntı operatörü olarak rcdesteklemediği durumlar dışında alıntı yapmak zarar vermez \).

Arka /bölgesindeki /dest/dir/çok olmasıdırmv yerine adlandırma bir hata ile başarısız foo.cppiçin /dest/dirsadece bir yerde durumda cppdosya bulunmuştur ve /dest/dirmevcut olmayan ya da bir dizin (veya dizine sembolik link) değildi.


+1 ... bir komutun çalıştırılmasının ön koşulu olarak kabuk içi işlem aslında çeşitli kullanım durumları için kullanışlıdır ... güzel.
Cbhihe

0
find . -name "*.mp3" -exec mv --target-directory=/home/d0k/Музика/ {} \+

Lütfen cevabınıza başkalarının öğrenebileceği bir açıklama ekleyin
Nico Haase

Açıklama isteyen soruyu cevaplamanız gerekiyor. Yalnızca kod bir yanıt değildir.
Lajos Arpad

-1

hayır, arasındaki fark +ve \;ters çevrilmelidir. +dosyaları exec komutunun sonuna ekler, ardından exec komutunu \;çalıştırır ve her dosya için komutu çalıştırır.

Sorun is find . -type f -iname '*.cpp' -exec mv {} ./test/ \+olmalıdır find . -type f -iname '*.cpp' -exec mv {} ./test/ + gerek ondan kaçmak veya sonlandırmak için+

xargs uzun zamandır kullanmadığım halde + gibi çalıştığını düşünüyorum.


Bunu da denedim ama aynı hata mesajını aldım. Dahası, her yerde sadece + kullandığım halde cygwin'imde çalışmak için \ + veya "+" kullanmam gerekiyor.
Shahadat Hossain

oh bu bir cygwin ortamı. Üzgünüm o zaman bilmiyorum, cygwin kabuğunu kullanmıyorum, sadece * nix kullanıyorum.
Mike Ramirez

1
@Shahadat Hossain deniyor -name "*.cpp"-iname '??? iş gibi zor bir normal ifade araması yapmak istemiyorsam -iname'i pek kullanmıyorum. * \. Cpp'
Mike Ramirez

1
@Mike: Sanırım -inameve arasındaki farkı yanlış anladınız -name. normal ifadelerin büyük / -inameküçük harfe duyarlı olmayan sürümüdür -nameve bunların işlenmesinde hiçbir fark yoktur. Göndermeden önce komutları denemenizi öneririm, komutunuz kabuğumda da başarısız oluyor.
Lekensteyn

1
@Lekensteyn Yorumunuzdan önce durum zaten belirlenmişti. Gönderinizden önce Shahadat'ı kabul ettiğimi sanıyordum, basit bir "tamam" idi. Hayır, manuel olarak çalıştırmadım, başımın tepesinden yaptım ve bul ile bu normal ifade biçimini nadiren kullandım. Bu sadece 'yardımcı olabilir' türü bir şeydi.
Mike Ramirez
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.