bul | xargs shasum sağlama toplamı dosyasının kendisini sağlama toplamı oluşturur (erken) ve kontrol ederken başarısız olur


10

Benim sorunum (ile bir komut dosyasında #!/bin/sh) aşağıdaki gibidir: Bir dizindeki tüm dosyaları arşivleme amacıyla sağlama toplamı. Tüm dosya adlarına sahip sağlama toplamı (benim durumumda sha1) dosyası aynı dizinde bulunmalıdır. Diyelim ki ~/testdosya f1ve f2: içeren bir dizinimiz var .

mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2

Şimdi sağlama toplamlarını

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum

tam olarak ne istediğimi yapar, sadece geçerli dizinin tüm dosyaları listeler ve sha1 toplamlarını hesaplar (maxdepth daha sonra değiştirilebilir). STDOUT'taki çıktı:

f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2

Ne yazık ki, bunu bir dosyaya kaydetmeye çalışırken

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1

sonuçta ortaya çıkan dosya kendisi için sağlama toplamını görüntüler:

da39a3ee5e6b4b0d3255bfef95601890afd80709  sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2  

ve bu nedenle shasum --check, son toplamı kaydederken ek dosya değişikliği sorunu nedeniyle daha sonra başarısız olur .

Etrafa baktım ve -pbayrağını kullanarak xargs, bul komutunu çalıştırmadan önce bir şekilde çıktı dosyasını oluşturduğunu öğrendim, bu nedenle ek dosya bulundu ve kontrol edilecek ...

Bir geçici çözüm olarak, sağlama toplamı başka bir konuma (geçici dizin yoluyla mktemp) kaydedebilir veya özel olarak bulmakta hariç tutabileceğini biliyorum, ama neden böyle davrandığını anlamak istiyorum - ki gözlerimde bu kadar kullanışlı değil, örneğin, ilk komut çıktı dosyasının zaten diskte olup olmadığını kontrol ederse, asla doğru cevabı alamaz ...


8
O değil xargsçünkü bu dosya oluşturur kabuk kendisidir, daha önce herhangi bir komut öncelikle kabuk yönlendirir tüm giriş, çıkış ve boruları çalıştırıldığında, böylece findçıkış dosyasını başlatır zaten var. -execBunun yerine kullanın :find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
jimmij

@jimmij, birkaç shçağırma gerektiğinde bunun çalışması garanti edilmez . Daha $0önce tartışmanız gerektiğini unutmayın {}.
Stéphane Chazelas

@jimmij Önerilen diğer cevabınız teekayboldu mu? Ben denedim ve iyi çalışıyor, ben de ekleyerek STDOUT bastırdı 1>/dev/null. Cevabı yanlış olan bir şey mi vardı yoksa bir hata mı?
user121391

Stephane, bazen doğru görünen yarış durumu problemi olabileceğine dikkat çekti. Bakabilmek için bir süre geri aldım, ancak listede çok sayıda dosya varsa bu komut yanlış olabilir.
jimmij

@jimmij ah, anlıyorum. Sorunlar hakkında bir uyarı ile ön eklerseniz faydalı olabilir, çünkü bunun olabileceği çok iyi bilinmediğini düşünüyorum. Aksi takdirde, yinelenen çalışmalar eski dosyayı ve üzerine yazılması gereken durumlar için Anthon'ları içeriyorsa, durumlar için cevabınızı kabul ederdim.
user121391

Yanıtlar:


12

Dosyanın şunlara erişmesini engelleyebilirsiniz xargs:

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\n' |
  xargs -r shasum -- > sums.sha1

Dosya adlarında boşluklar, yeni satırlar, tırnak işaretleri veya ters eğik çizgiler olan sorunları önlemek için şunu kullanırdım:

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\0' |
  xargs -r0 shasum -- > sums.sha1

yerine.

--İle başlayan dosya adları ile ilgili sorunları önlemektir -. Ancak adlı bir dosya için yardımcı olmaz -. -print0Bunun yerine kullanmış -printf '%P\0'olsaydınız --, -dosyayla ilgili bir sorun yaşamazdınız ve olmazdı .


Senin çözümün sonunda kullandığım şeydi. Özellikle sonraki çalışmalarda sağlama toplamı dosyasını yeniden değil ve dizini inflat gibi. Ayrıca, benim komut dosyasında basenameverilen tam yoldan sums.sha1 dosya adını alırdım (bu soruya dahil edilmedi, ancak başkalarına yardımcı olabilir).
user121391

7

Kullandığınız için -maxdepth 1, özyineleme istemediğinizi varsayıyorum. Öyleyse, bunun yerine kabukta yapın:

for f in ~/test/*; do
    shasum -- "$f"
done > sums.sha1

Dizinleri atlamak için şunları yapabilirsiniz:

for f in ~/test/*; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

Özyinelemeye ihtiyacınız varsa ve kullanıyorsanız bash, şunları yapın:

shopt -s globstar
for f in ~/test/**; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

Tüm bu yaklaşımların boşluklu, yeni satırlı veya başka herhangi bir şey içeren rasgele dosya adları üzerinde çalışma avantajına sahip olduğunu unutmayın.


Bence bu OP'nin içinde yeni satırları olan dosya isimleriyle ilgili her türlü sorunu çözdüğünden bahsederdiniz. Öte yandan, eğer sums.sha1zaten mevcutsa (önceki bir çalışmadan) çözümünüz onu dahil edecektir.
Anthon

Üzgünüz, daha önce açıklığa kavuşturmadım: maxdepth sadece bu örnekte kullanıldı, şu anda sadece 1 derinliğe ihtiyacım olmasına rağmen, kullanıcı / komut dosyasının herhangi bir değer sağlayabildiği bir işlev kullanıyorum.
user121391

@ user121391 özyinelemeli bir yaklaşım için güncellenmiş cevaba bakın.
terdon

Ayrıca, borular, cihazlar ... (ve bunlara semboller) gibi diğer normal olmayan dosyaları da kontrol etmeye çalışacağını unutmayın.
Stéphane Chazelas

Teşekkür ederim, şahsen kullanıyorum sh, ancak cevabınız başkalarına yardımcı olabilir.
user121391

4

ile zsh:

shasum -- *(D.) > sums.sha1

Glob, yeniden yönlendirme yapılmadan önce genişletilecektir, bu yüzden sums.sha1ilk etapta orada değilse dahil edilmeyecektir.

Dnokta dosyalarını (gizli dosyalar) olduğu gibi eklemektir find. .yalnızca normal dosyaları (sizin gibi -type f) seçmektir .

Her şeyden önce sums.sha1olması durumunda yine de hariç tutmak için :

setopt extendedglob # best in ~/.zshrc
shasum -- ^sums.sha1(D.) > sums.sha1

Bunların bir shasum komutu çalıştırdığına dikkat edin, böylece liste çok büyükse "Arg listesi çok uzun" hatasıyla karşılaşabilirsiniz. Bu sorunu çözmek için:

autoload zargs
zargs -e/ -- *(D.) / shasum > sums.sha1

Adlı bir dosya ile olası sorunları önlemek için ./*yerine kullanmanızı tavsiye ederim .*-


Soruyu kabuk türüyle düzenledim, ancak cevabınız bana bir süre önce
zsh'a

1

Diğer yanıtların daha önce belirttiği gibi, sorun, sums.sha1kablonuzu boru hattınızı çalıştırmadan önce açar ve oluşturur . Birçok dağıtım paketinin spongeparçası olan programı kullanabilirsiniz moreutils. Kabuk yeniden yönlendirmesinin aksine sponge, dosyayı açmadan önce her şeyi alana kadar bekler. Genellikle aynı kanalda okuduğunuz bir dosyayı yazmak istediğinizde kullanılır.

Sizin durumunuzda şu şekilde kullanılır:

$ find -maxdepth 1 -type f -printf '%P\n' |xargs shasum |sponge sums.sha1
$ cat sums.sha1
31836aeaab22dc49555a97edb4c753881432e01d  B
7d157d7c000ae27db146575c08ce30df893d3a64  A

0

Bul / xargs vs alternatif olarak sha1deep isteyebilirsiniz. Muhtemelen farklı bir pakette - kutumda md5deep paketinde geliyor.

Diğerlerinin söylediği gibi, sums.sha1, kabuk başlamadan, buluntu başlamadan önce yaratılır. İle bir hile ! -name sums.sha1ile findirade olarak, çalışacak

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum | grep -v ' sums\.sha1$' > sums.sha1
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.