değişken genişleme ile bash komut dosyasında find -exec


14

Bir bash komut dosyasında aşağıdakine benzer bir komut çalıştırmaya çalışıyorum. Tüm alt klasörleri aramalı $sourcedirve belirli bir türdeki tüm dosyaları kök düzeyine kopyalamalıdır $targetdir.

#!/bin/bash

# These are set as arguments to the script, not hard-coded
sourcedir="/path/to/sourcedir"
targetdir="/path/to/targetdir"

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2/`basename "$1"`"' "{}" "$targetdir" \;

Dışında bu, oldukça yakın görünüyor {}olarak değil geçirilen $2için-exec sh -c ...

Bunu dosya adlarındaki özel karakterlere (özellikle tek tırnak karakterlerine) toleransla, mümkün olduğunca "doğru yola" yakın yapmak istiyorum.

Düzenleme: Ben insanlar kullanarak xargsveya argüman zincirleme önermek görüyorum . Bunun sadece sınırlı sayıda argüman için iyi olduğu izlenimindeydim. Örneğin, galeri dizinlerinden birkaçını dev bir slayt gösterisi dizinine kopyalamaya çalıştığım binlerce .jpg dosyası varsa, argümanları zincirleyen çözümler hala çalışır mı?

Düzenleme 2: Benim sorunum bir komutta _sh benim ilk seçenek önce eksik oldu -exec. Find komutunun nasıl çalışacağını merak eden herkes için şunu ekleyin _ve her şey yoluna girecektir:

find "$sourcedir" -type f -name "*.type" -exec sh -c 'cp "$1" "$2"' _ "{}" "$targetdir" \;

Yine de aynı cevabı yerine getirdiğinden, ancak daha verimli ve zarif olduğu için aşağıdaki cevabı kabul ettim.


4
Sınırlı xargsnormal komutlarda büyük miktarlarda argümanı otomatik olarak ele almak için neden bu kadar yaratıldığı tam olarak budur . Ayrıca, maksimum argüman sınırlarının çoğunun standart GNU araçları için büyük ölçüde geliştirildiğini dikkate almak gerekir. Ayrıca binlerce dosyada ilgili olan tüm bu işlem çatallarından kaçınarak bir performans avantajı göreceksiniz.
JM Becker

";" Yerine gnu-find ve + ile, find ile aynı anda birden fazla argümanı işleyebilirsiniz. Ve -print0 ile geçen karmaşık argümanı kaydedersiniz.
kullanıcı bilinmiyor

@userunknown: Buna cevabınızın altında cevap veriyorum.
JM Becker

@user unknown Pekala, bu kodu SEVİYORUM. En azından POSIX uyumludur ve makinede hiç GNU olmadan çalışır. Ne zaman o zamanlar vardır do özellikle iş yerinde sunucularda, buna ihtiyacım var.
syntaxerror

Yanıtlar:


6

Belirli bir türdeki dosyaları belirli bir dizine mi kopyalamak istiyorsunuz? Bu en iyi şekilde yapılır xargsve buna bile ihtiyacınız yoktur sh. Bu daha uygun bir yöntemdir, daha verimli çalışmalıdır.

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

Özel dosya adlarını işlemeniz gerekiyorsa NULLayırıcı olarak kullanın

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"

1
2 durum için, eklemeyi unutmayın -print0etmek findve -0karşıxargs
SiegeX

@ SiegeX, yorumunuzu fark etmeden zaten bunu yapıyordum.
JM Becker

Ayrıca, NULLkullanmanız gerekli değildir '{}', kullanmadığınız zaman önemlidir. POSIXUyumluluk dışında, diğeri arasındaki gerçek fayda performanstır.
JM Becker

6

Kabuğa {}bir argüman olarak geçmeniz ve ardından her argümanın üzerinden geçmeniz gerekir.

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

Not : Bunun nasıl çalıştığı bir kabuğa ilk argüman kabuğun adıdır , adı olarak geçirerek $targetdirbundan yararlanabiliriz ve sonra $0bu targetdir'e erişmek için kabuk betiğinin içindeki özel parametreyi kullanabiliriz .


1
"$targetdir"tek tırnak içinde genişletilmez.
enzotib

5

Eğer xargs kilisesine inanmıyorsanız:

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

Açıklama:

cp -t a b c d 

b, c ve d kopyalarını hedef dizine a kopyalar.

-exec cmd {} +

komutu bir seferde büyük bir grup dosyaya çağırır, birbiri ardına değil (bunun ";"yerine standart olarak kullanılır +). Bu nedenle targetdir'i öne doğru çekmek ve açıkça hedef olarak işaretlemek zorundasınız.

Bu gnu-find için çalışır ve diğer find uygulamaları için geçerli olmayabilir. Tabii ki -t-işaretine dayanır.

TechZilla elbette şu ana kadar, cp'yi shçağırmak için gerekli değil.

xargsKullanmıyorsanız, çoğu zaman birlikte kullanılmaya ihtiyaç duymazsanız find, -print0ve -0işaretini öğrenmekten kurtulmuş olursunuz .


1
Açıkçası, kimsenin tercih edebileceği yöntem biraz özneldir. Bununla birlikte, hala kullanmak için nedenler var xargs. En büyük örnek, dosyaları bulamıyorsanız ne olacak? Her forzaman genel döngüler yerine xargs kullanıyorum find, kapsamı çok daha küçük. Ayrıca, findyalnızca +GNU kullanıyorsanız POSIX'te findtanımlanmadığını destekler. Bu yüzden findyalnız tercih etmekten çekinmeyin , xargs'ın yaptığı her şeyi yapmaz. GNU'yu xargsdüşündüğünüzde -P, çok çekirdekli olan da elde edersiniz . Ne xargsolursa olsun öğrenmeye değer .
JM Becker

Öznellik konuşma, benim görüşüm açıkça farklıdır. Nesnel olarak, cevabınız da doğrudur. Mevcut en iyi çözümlerden biridir.
JM Becker

@TechZilla: Bulma paralel çağrıları desteklemeye başladığında bu siteyi tekrar ziyaret etmeyi umuyorum. :) Kopyalama / taşıma ile çoğu durumda, disk hızı sınırlayıcı faktör olacaktır, ancak SSD'ler resmi değiştirebilir. Haklısınız, sağlamak için GNU olmayan bir çözüm iyi bir şey. Aksi takdirde, bulma çözümü nesnel olarak daha kısa, daha basittir ve yalnızca iki işlem kullanır.
kullanıcı bilinmiyor

0
read -p "SOURCE: " sourcedir
read -p "TYPE: " type
read -p "TARGET: " targetdir
find -L $sourcedir -iname "*.$type" -exec cp -v {} $targetdir \;

3
Çözümünüzle ilgili bazı açıklamalar ekleyin.
HalosGhost
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.