Backtick (veya $ (...)) genişlemesindeki boşlukları korumanın bir yolu yok mu?
Hayır, yok. Neden?
Bash'in neyin korunması gerektiğini ve nelerin olmaması gerektiğini bilmesinin bir yolu yoktur.
Unix dosyasında / kanalında diziler yok. Sadece bir bayt akışı. ``
Veya içindeki komut $()
, bash yutar ve tek bir dize gibi davranan bir akış çıkarır. Bu noktada, sadece iki seçeneğiniz var: onu tek bir dize olarak tutmak için tırnak içine alın veya çıplak yapın, böylece bash yapılandırılmış davranışına göre böler.
Öyleyse, bir dizi istiyorsanız, bir dizi içeren bir bayt formatı tanımlamak xargs
ve find
yapmanız gereken ve aşağıdaki gibi araçların yapmak zorunda olduğunuz şeydir : Bunları -0
argüman ile çalıştırırsanız , öğeleri sonlandıran ikili bir dizi formatına göre çalışırlar. null bayt, aksi takdirde opak bayt akışına semantik ekler.
Ne yazık ki, bash
boş bayttaki dizeleri ayıracak şekilde yapılandırılamaz. Bize bunu yapabildikleri için /unix//a/110108/17980 adresine teşekkürler zsh
.
xargs
Komutunuzun bir kez çalışmasını istiyorsunuz ve bunun xargs -0 -n 10000
sorununuzu çözdüğünü söylediniz . Bu, 10000'den fazla parametreniz varsa, komutunuzun bir kereden fazla çalışmasını sağlar.
Kesinlikle bir kez çalışmasını veya başarısız olmasını istiyorsanız, -x
argümanı ve -n
argümandan daha büyük bir argümanı sağlamanız gerekir -s
(gerçekten: bir grup sıfır uzunluklu argüman artı komutun isminin sığmaması için yeterince büyük -s
boyutu). ( adam xargs , aşağıdan alıntıya bakınız)
Şu anda bulunduğum sistemin 8M ile sınırlı bir yığını var, işte benim sınırım:
$ printf '%s\0' -- {1..1302582} | xargs -x0n 2076858 -s 2076858 /bin/true
xargs: argument list too long
$ printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true
(no output)
darbe
Harici bir komut eklemek istemiyorsanız, /unix//a/110108/17980 adresinde gösterildiği gibi bir diziyi beslerken while-read döngüsü, bash'ın şeyleri bölmesinin tek yoludur. boş bayt.
( . ... "$@" )
Yığın boyutu sınırını önlemek için komut dosyasını kaynak fikri harika (denedim, işe yarıyor!), Ancak normal durumlar için muhtemelen önemli değil.
Stdin'den başka bir şey okumak istiyorsanız, işlem borusu için özel bir fd kullanmak önemlidir, ancak aksi takdirde buna ihtiyacınız olmaz.
Yani, günlük ev ihtiyaçları için en basit "yerel" yol:
files=()
while IFS= read -rd '' file; do
files+=("$file")
done <(find ... -print0)
myscriptornonscript "${files[@]}"
İşlem ağacınızı temiz ve güzel görünmesini isterseniz, bu yöntem exec mynonscript "${files[@]}"
, bash işlemini bellekten kaldırır ve çağrılan komutla değiştirir. xargs
komut yalnızca bir kez çalışsa bile, çağrılan komut çalışırken her zaman bellekte kalır.
Yerel bash yöntemine karşı konuşan şey şudur:
$ time { printf '%s\0' -- {1..1302581} | xargs -x0n 2076858 -s 2076858 /bin/true; }
real 0m2.014s
user 0m2.008s
sys 0m0.172s
$ time {
args=()
while IFS= read -rd '' arg; do
args+=( "$arg" )
done < <(printf '%s\0' -- $(echo {1..1302581}))
/bin/true "${args[@]}"
}
bash: /bin/true: Argument list too long
real 107m51.876s
user 107m38.532s
sys 0m7.940s
bash dizi işleme için optimize edilmemiştir.
adam xargs :
-n max-args
Komut satırı başına en fazla max-args argümanı kullanın. -X seçeneği belirtilmedikçe, boyut (-s seçeneğine bakın) aşılırsa, max-args değerinden daha az bağımsız değişken kullanılır; bu durumda xargs çıkar.
-s max-chars
Komut ve ilk bağımsız değişkenler ve bağımsız değişken dizelerinin sonlarındaki sonlandırma null'ları dahil olmak üzere komut satırı başına en fazla max karakter karakteri kullanın. İzin verilen en büyük değer sisteme bağlıdır ve exec için bağımsız değişken uzunluğu sınırı, ortamınızın boyutu daha az, 2048 baytlık daha az boş alan olarak hesaplanır. Bu değer 128 KB'den fazlaysa, varsayılan değer olarak 128Kib kullanılır; aksi takdirde, varsayılan değer maksimum değerdir. 1 KB 1024 bayttır.
-x
Boyut aşılırsa (-s seçeneğine bakın) çıkın.
IFS="
, yeni satır"
). Ancak komut dosyasını tüm dosya adları üzerinde yürütmeye gerek var mı? Değilse, her dosya için komut dosyasını yürütmek üzere find komutunu kullanmayı düşünün.