Kabul edilen / yüksek oylanan cevaplar harika, ancak birkaç cesur ayrıntıdan yoksunlar. Bu yazı, dosya adları gömülü yeni satırlar / tire simgeleri içerdiğinde ve sonuçları bir dosya.
Kabuk glob genişletmesini kullanarak , dizinde hiçbir dosya *
yoksa ve istenmeyen sonuçlara neden olabilecek çalıştırılacak komuta genişletilmemiş bir glob dizesi geçirilirse genişletmenin başarısız olma olasılığı vardır . Kabuk bu kullanmak için genişletilmiş bir kabuk seçeneği sağlar . Böylece döngü temelde dosyalarınızı içeren dizinin içinde aşağıdaki gibi olurbash
nullglob
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
Bu, ifade ./*
herhangi bir dosya döndürmediğinde (dizin boşsa) for döngüsünden güvenle çıkmanızı sağlar.
veya POSIX uyumlu bir şekilde ( nullglob
bir bash
spesifik)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
Bu, ifade bir kez başarısız olduğunda döngüye girmenizi sağlar ve koşul [ -f "$file" ]
, genişletilmemiş dizenin ./*
söz konusu dizinde geçerli olmayacak geçerli bir dosya adı olup olmadığını kontrol eder . Bu durumda başarısızlık durumunda, daha sonra çalışmayacak olan döngüye continue
geri dönüyoruz for
.
Ayrıca --
dosya adı bağımsız değişkenini geçmeden hemen önce kullanıldığına dikkat edin . Bu gereklidir, çünkü daha önce belirtildiği gibi, kabuk dosya adları dosya adının herhangi bir yerinde tire içerebilir. Kabuk komutlarının bazıları bunu yorumlar ve ad düzgün bir şekilde tırnak içine alınmadığında bir komut seçeneği olarak görür ve bayrak sağlanırsa komut düşüncesini yürütür.
Bu --
durumda komut satırı seçeneklerinin sonuna işaret eder, yani komut bu noktanın ötesinde herhangi bir dizeyi komut bayrağı olarak ayrıştırmamalı, yalnızca dosya adları olarak ayrılmalıdır.
Dosya adlarının iki kez tırnak içine alınması, isimler glob karakterler veya boşluklar içerdiğinde durumları düzgün şekilde çözer. Ancak * nix dosya adları bunlarda yeni satırlar da içerebilir. Dolayısıyla, dosya adlarını geçerli bir dosya adının parçası olamayacak tek karakterle sınırlandırıyoruz - null byte ( \0
). Yana bash
dahili olarak kullandığı C
boş bayt dize sonunu belirtmek için kullanıldığı tarzı dizeleri, bunun için doğru aday.
Bu nedenle , komut seçeneğini printf
kullanarak bu NULL bayt ile dosyaları sınırlamak için kabuk seçeneğini kullanarak, aşağıda yapabiliriz-d
read
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
Ve nullglob
ve printf
etrafları sarılır , bu da komutun bir kez çıkmasından sonra ana kabuğa yansıtma seçeneğinden (..)
kaçınmak için temel olarak bir alt kabukta (alt kabuk) çalıştırıldıkları anlamına gelir nullglob
. -d ''
Seçeneği read
komuta olduğunu değil yani ihtiyacı POSIX uyumlu bash
bunun yapılması gerek için kabuk. Kullanımı find
bu kadar yapılabilir komut
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
İçin find
desteklemeyen uygulamalarda -print0
(GNU ve FreeBSD uygulamaları hariç), bu kullanılarak taklit edilebilirprintf
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
Diğer önemli bir düzeltme, çok sayıda dosya G / Ç'sini azaltmak için yeniden yönü for-loop'un dışına taşımaktır. Döngü içinde kullanıldığında, kabuk for-loop'un her yinelemesi için sistem çağrılarını iki kez, bir kez açılmak ve bir kez dosya ile ilişkili dosya tanımlayıcıyı kapatmak için yürütmek zorundadır. Bu, büyük iterasyonlar yürütme performansınızda bir şişe boynu haline gelecektir. Önerilen öneri onu döngü dışına taşımak olacaktır.
Yukarıdaki kodu bu düzeltmelerle genişleterek şunları yapabilirsiniz:
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
temel olarak dosya girişinizin her yinelemesi için komutunuzun içeriğini stdout'a koyar ve döngü sona erdiğinde, stdout'un içeriğini yazmak ve kaydetmek için hedef dosyayı bir kez açın. Aynı eşdeğeri find
sürümü
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out