Printf komutunu kullanarak bir karakteri N kez yazma


12

Linux'ta bir karakteri tekrarlamak için aşağıdaki komutu buldum:

printf 'H%.0s' {1..5000} > H.txt

Örneğin, zamanları Htekrarlamak istiyorum 5000. %.0sBurada ne anlama geliyor?


İle tcshya da zsh, repeat 5000 printf Hanlamak kolaydır. İle perl: print "H" x 5000(o notu {1..5000}esinlenerek Zsh operatörüdür perls' 1..5000bir ve daha sonra ksh93 ve bash tarafından kopyalanan)
Stéphane Chazelas

evet çalışıyor, ancak daha fazla tekrar için çok fazla kaynak kullanıyor, Stéphane Chazelas
Skaperen

1
bu komutu yes H|head -5000|tr -d '\012'
yapardım

dd if=/dev/zero bs=5000 count=1 | tr '\0' H
kojiro

@Skaepren:yes H| head -n 2500| tr \\n H
mikeserv

Yanıtlar:


20

Bu komut, 5000 argüman üreten kabuk bağlıdır ve bunları geçen için printfbu daha sonra bunları yok sayar. Oldukça hızlı görünse de - ve bazı şeylere göreceli olsa da - kabuk yine de tüm bu dizeleri argümanlar (ve onları sınırlar) olarak üretmelidir .

Oluşturulan H'lerin, kabuk ilk kez 5000'e kadar tekrarlanana kadar yazdırılamamasının yanı sıra, bu komut, sayısal dize bağımsız değişkenlerini printf artı H'lere depolamak ve sınırlamak için gereken tüm belleğe de mal olur . Tıpkı yapabileceğiniz gibi:

printf %05000s|tr \  H

... 5000 boşluktan oluşan bir dize oluşturur - ki bu en azından genellikle başına tek bir bayttır ve sınırlandırılmadığı için sınırlandırılması hiçbir ücrete tabi değildir. Birkaç test, 5000 bayt kadar az bir süre için trbile, bu durumda bile çatalın ve gereken borunun maliyetinin buna değdiğini ve neredeyse her zaman sayıların arttığı zamandır.

Koştum ...

time bash -c 'printf H%.0s {1..5000}' >/dev/null

...ve...

time bash -c 'printf %05000s|tr \  H' >/dev/null

Her biri yaklaşık 5 kez bir parça (burada bilimsel bir şey yok - sadece anekdot) ve destek genişletme sürümü toplam işlem süresinde ortalama .02 saniyenin biraz üzerinde, ancak trsürüm ortalama olarak yaklaşık 0,012 saniyede geldi - ve trsürüm onu ​​dövdü her zaman. Sürpriz olduğumu söyleyemem - {brace expansion}kullanışlı bir interaktif kabuk stenografi özelliğidir, ancak genellikle herhangi bir komut dosyası söz konusu olduğunda yapmak oldukça zahmetli bir şeydir. Ortak form:

for i in {[num]..[num]}; do ...

... bunu düşündüğünüzde, gerçekten iki for döngü - birincisi içseldir ve kabuğun, bunları kaydetmeden ve fordöngü için tekrar yinelemeden önce bu yineleyicileri oluşturmak için bir şekilde döngü yapması gerektiği anlamına gelir . Bu tür şeyler genellikle daha iyi yapılır:

iterator=$start
until [ "$((iterator+=interval))" -gt "$end" ]; do ...

... çünkü yalnızca çok az bir değer depolar ve yinelemeleri oluştururken yinelemeyi yaparken gittikçe bunların üzerine yazarsınız.

Her neyse, daha önce belirtilen boşluk dolgusu gibi, printfelbette, rastgele sayıda rakamı sıfırlamak için de kullanabilirsiniz :

printf %05000d

Bir argüman bulunmadığında printf'sd dizesinde belirtilen her argüman için null dize kullanılır - bir basamak argümanı için sıfır veya bir dize için boş bir dize olarak yorumlanır, çünkü her iki bağımsız değişken yapmam .

Bu, söz konusu komutla karşılaştırıldığında madalyonun diğer (ve bence - daha verimli) tarafıdır - printf %.0her bir argüman için dizeleri uzatırken yaptığınız gibi bir şey almak mümkün değildir , bu yüzden de hiçbir şeyden bir şey almak mümkün.

Aşağıdaki ddgibi kullanabileceğiniz büyük miktarda oluşturulan bayt için daha hızlı :

printf \\0| dd bs=64k conv=sync 

... ve w / düzenli dosyalar dd'ın seek=[num]argümanı daha avantaj kullanılabilir. Eğer eklerseniz 64k yeni satır yerine boş değerlere alabilirsiniz ,unblock cbs=1satır başına keyfi dizeleri ile orada enjekte edebilir üstünde ve ila pasteve /dev/null- ama bu durumda, sizin için kullanılabilir olduğunda siz de kullanabilirsiniz:

yes 'output string forever'

İşte ddyine de bazı örnekler:

dd bs=5000 seek=1 if=/dev/null of=./H.txt

... yaratan (veya kesikler) bir \0NULboyut 5000 bayt H.txt adında geçerli dizinde dolu dosyayı. dddoğrudan ofseti arar ve NUL arkasını doldurur.

<&1 dd bs=5000 conv=sync,noerror count=1 | tr \\0 H >./H.txt

... aynı ad ve büyüklükte ancak H karakterleriyle doldurulmuş bir dosya oluşturur. Bu yararlanır ddzaman okuma hatası durumunda en az bir tam boş-bloğun yazma 'ın spec' davranış noerrorve syncdönüşümler belirtilmiştir (- olmadan ve count=muhtemelen tercih edebilir daha uzun devam edecek -) yönlendirmeleri ve kasıtlı wdineonly dosya tanıtıcısı dd.


8

%.0sBir şekilde argüman dönüştürmek demektir dize bir ile, hassas sıfır. Buna göre man 3 printf, böyle bir durumda hassas değer verir

   [ ... ] the  maximum  number  of characters to be printed from a
   string for s and S conversions.

bu nedenle kesinlik sıfır olduğunda, dize bağımsız değişkeni hiç yazdırılmaz. Ancak Hargümanlar olduğu gibi (ki biçim belirteci parçası olan) göre yana sayıda bastırılır alır printfbölümündeman bash

The format is reused as necessary to consume all  of  the  argu
ments.  If the format requires more arguments than are supplied,
the extra format specifications behave as if  a  zero  value  or
null  string,  as  appropriate,  had  been supplied. 

7

Bu durumda, %.0sher zaman önüne bir karakter örneği, bu durumda H yazar. {1..5000} kullandığınızda, kabuk onu genişletir ve şöyle olur:

printf 'H%.0s' 1 2 3 4 ... 5000 > H.txt

yani, printf komutunun artık 5000 bağımsız değişkeni vardır ve her bağımsız değişken için bir H alırsınız. Bunların sıralı veya sayısal olması gerekmez:

printf 'H%.0s' a bc fg 12 34

yazdırır HHHHH- yani, bu durumda argüman sayısı 5.

Not, yukarıdaki 1. örnekteki elipsler tam anlamıyla eklenmez, bir sıra veya aralığı belirtmek için oradadırlar.

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.