Dengan tcshatau zsh, repeat 5000 printf Hlebih mudah dimengerti. Dengan perl: print "H" x 5000(catatan bahwa {1..5000}adalah operator zsh terinspirasi oleh perl's 1..5000satu dan kemudian disalin oleh ksh93 dan bash)
Stéphane Chazelas
ya itu berhasil, tetapi menggunakan banyak sumber daya untuk pengulangan yang lebih besar, ikuti saran oleh Stéphane Chazelas
Skaperen
1
saya akan melakukan perintah iniyes H|head -5000|tr -d '\012'
Skaperen
dd if=/dev/zero bs=5000 count=1 | tr '\0' H
kojiro
@Sepepren:yes H| head -n 2500| tr \\n H
mikeserv
Jawaban:
20
Perintah itu tergantung pada shell yang menghasilkan 5000 argumen, dan meneruskannya printfyang kemudian mengabaikannya. Meskipun mungkin terlihat cukup cepat - dan relatif untuk beberapa hal - shell masih harus menghasilkan semua string sebagai args (dan membatasi mereka) dan seterusnya.
Selain fakta bahwa Hs yang dihasilkan tidak dapat dicetak sampai shell pertama kali beralih ke 5000, perintah itu juga menghabiskan semua memori yang diperlukan untuk menyimpan dan membatasi argumen string numerik menjadi printfditambah Hs. Sederhananya yang dapat Anda lakukan:
printf %05000s|tr \ H
... yang menghasilkan string 5000 ruang - yang, setidaknya, biasanya hanya satu byte per dan tidak ada biaya untuk membatasi karena tidak dibatasi. Beberapa tes menunjukkan bahwa bahkan untuk sedikitnya 5.000 byte biaya garpu dan pipa yang diperlukan untuk tritu layak bahkan dalam kasus ini, dan hampir selalu adalah ketika jumlahnya semakin tinggi.
Saya berlari ...
time bash -c 'printf H%.0s {1..5000}'>/dev/null
...dan...
time bash -c 'printf %05000s|tr \ H'>/dev/null
Masing-masing sekitar 5 kali sepotong (tidak ada yang ilmiah di sini - hanya anekdotal) dan versi ekspansi brace rata-rata sedikit lebih dari 0,02 detik dalam total waktu pemrosesan, tetapi trversi datang sekitar rata-rata total 0,012 detik - dan trversi mengalahkannya setiap saat. Saya tidak bisa mengatakan saya terkejut - {brace expansion}adalah fitur steno shell interaktif yang berguna, tetapi biasanya hal yang agak boros untuk dilakukan di mana pun jenis scripting yang bersangkutan. Bentuk umum:
for i in{[num]..[num]};do...
... ketika Anda memikirkannya, benar-benar duafor loop - yang pertama adalah internal dan tersirat dalam bahwa shell harus diulang dengan cara tertentu untuk menghasilkan iterator sebelum menyimpan semuanya dan mengulanginya lagi untuk forloop Anda . Hal-hal seperti itu biasanya lebih baik dilakukan seperti:
... karena Anda menyimpan nilai yang sangat sedikit dan menimpa mereka saat Anda pergi serta melakukan iterasi saat Anda menghasilkan iterables.
Pokoknya, seperti ruang yang disebutkan sebelumnya, Anda juga dapat menggunakan printfuntuk zeropad angka yang berubah-ubah, tentu saja, seperti:
printf %05000d
Saya melakukan keduanya tanpa argumen karena untuk setiap argumen yang ditentukan dalam printfformat string ketika sebuah argumen tidak ditemukan, string nol digunakan - yang ditafsirkan sebagai nol untuk argumen digit atau string kosong untuk string.
Ini adalah sisi lain (dan - menurut saya - lebih efisien) dari sisi koin jika dibandingkan dengan perintah dalam pertanyaan - sementara dimungkinkan untuk tidak mendapatkan apa pun dari sesuatu seperti yang Anda lakukan saat Anda printf %.0memanjang string untuk setiap argumen, demikian juga mungkin untuk mendapatkan sesuatu dari ketiadaan.
Masih lebih cepat untuk sejumlah besar byte yang dihasilkan yang dapat Anda gunakan ddseperti:
printf \\0| dd bs=64k conv=sync
... dan dddengan seek=[num]argumen file biasa dapat digunakan untuk keuntungan yang lebih besar. Anda bisa mendapatkan 64k baris baru daripada nol jika Anda menambahkan ,unblock cbs=1di atas dan dari sana bisa menyuntikkan string sewenang-wenang per baris dengan pastedan /dev/null- tetapi dalam hal itu, jika tersedia untuk Anda, Anda mungkin sebaiknya menggunakan:
yes 'output string forever'
Berikut ini beberapa ddcontoh lagi:
dd bs=5000 seek=1if=/dev/null of=./H.txt
... yang menciptakan (atau memotong) sebuah \0NULfile yang diisi dengan direktori saat ini bernama H.txt ukuran 5000 bytes. ddmencari langsung ke offset dan NUL-mengisi semua di belakangnya.
<&1 dd bs=5000 conv=sync,noerror count=1| tr \\0 H >./H.txt
... yang membuat file dengan nama dan ukuran yang sama tetapi diisi dengan karakter w. Ini mengambil keuntungan dari ddperilaku spesifik menulis setidaknya satu nol blok penuh jika terjadi kesalahan baca ketika noerrordan synckonversi ditentukan (dan - tanpa count=- kemungkinan akan berlangsung lebih lama dari yang Anda inginkan) , dan dengan sengaja mengarahkan ulang deskriptor file writeonly dddi stdin.
The %.0sberarti untuk mengkonversi argumen sebagai tali , dengan presisi dari nol. Menurut man 3 printf, nilai presisi dalam kasus seperti itu memberi
[...] the maximum number of characters to be printed from a
string for s and S conversions.
karenanya ketika presisi adalah nol, argumen string tidak dicetak sama sekali. Namun H(yang merupakan bagian dari penentu format) akan dicetak sebanyak yang ada argumen, karena sesuai dengan printfbagianman 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.
Dalam hal ini, %.0sselalu cetak satu instance karakter sebelumnya, H dalam hal ini. Saat Anda menggunakan {1..5000}, shell memperluasnya dan itu menjadi:
printf 'H%.0s'1234...5000> H.txt
yaitu, perintah printf sekarang memiliki 5000 argumen, dan untuk setiap argumen, Anda akan mendapatkan satu H. Ini tidak harus berurutan atau numerik:
printf 'H%.0s' a bc fg 1234
cetakan HHHHH- yaitu, jumlah argumen, 5 dalam hal ini.
Catatan, elips pada contoh 1 di atas tidak dimasukkan secara harfiah, mereka ada di sana untuk menunjukkan urutan atau rentang.
tcsh
atauzsh
,repeat 5000 printf H
lebih mudah dimengerti. Denganperl
:print "H" x 5000
(catatan bahwa{1..5000}
adalah operator zsh terinspirasi olehperl
's1..5000
satu dan kemudian disalin oleh ksh93 dan bash)yes H|head -5000|tr -d '\012'
dd if=/dev/zero bs=5000 count=1 | tr '\0' H
yes H| head -n 2500| tr \\n H
Jawaban:
Perintah itu tergantung pada shell yang menghasilkan 5000 argumen, dan meneruskannya
printf
yang kemudian mengabaikannya. Meskipun mungkin terlihat cukup cepat - dan relatif untuk beberapa hal - shell masih harus menghasilkan semua string sebagai args (dan membatasi mereka) dan seterusnya.Selain fakta bahwa Hs yang dihasilkan tidak dapat dicetak sampai shell pertama kali beralih ke 5000, perintah itu juga menghabiskan semua memori yang diperlukan untuk menyimpan dan membatasi argumen string numerik menjadi
printf
ditambah Hs. Sederhananya yang dapat Anda lakukan:... yang menghasilkan string 5000 ruang - yang, setidaknya, biasanya hanya satu byte per dan tidak ada biaya untuk membatasi karena tidak dibatasi. Beberapa tes menunjukkan bahwa bahkan untuk sedikitnya 5.000 byte biaya garpu dan pipa yang diperlukan untuk
tr
itu layak bahkan dalam kasus ini, dan hampir selalu adalah ketika jumlahnya semakin tinggi.Saya berlari ...
...dan...
Masing-masing sekitar 5 kali sepotong (tidak ada yang ilmiah di sini - hanya anekdotal) dan versi ekspansi brace rata-rata sedikit lebih dari 0,02 detik dalam total waktu pemrosesan, tetapi
tr
versi datang sekitar rata-rata total 0,012 detik - dantr
versi mengalahkannya setiap saat. Saya tidak bisa mengatakan saya terkejut -{brace expansion}
adalah fitur steno shell interaktif yang berguna, tetapi biasanya hal yang agak boros untuk dilakukan di mana pun jenis scripting yang bersangkutan. Bentuk umum:... ketika Anda memikirkannya, benar-benar dua
for
loop - yang pertama adalah internal dan tersirat dalam bahwa shell harus diulang dengan cara tertentu untuk menghasilkan iterator sebelum menyimpan semuanya dan mengulanginya lagi untukfor
loop Anda . Hal-hal seperti itu biasanya lebih baik dilakukan seperti:... karena Anda menyimpan nilai yang sangat sedikit dan menimpa mereka saat Anda pergi serta melakukan iterasi saat Anda menghasilkan iterables.
Pokoknya, seperti ruang yang disebutkan sebelumnya, Anda juga dapat menggunakan
printf
untuk zeropad angka yang berubah-ubah, tentu saja, seperti:Saya melakukan keduanya tanpa argumen karena untuk setiap argumen yang ditentukan dalam
printf
format string ketika sebuah argumen tidak ditemukan, string nol digunakan - yang ditafsirkan sebagai nol untuk argumen digit atau string kosong untuk string.Ini adalah sisi lain (dan - menurut saya - lebih efisien) dari sisi koin jika dibandingkan dengan perintah dalam pertanyaan - sementara dimungkinkan untuk tidak mendapatkan apa pun dari sesuatu seperti yang Anda lakukan saat Anda
printf %.0
memanjang string untuk setiap argumen, demikian juga mungkin untuk mendapatkan sesuatu dari ketiadaan.Masih lebih cepat untuk sejumlah besar byte yang dihasilkan yang dapat Anda gunakan
dd
seperti:... dan
dd
denganseek=[num]
argumen file biasa dapat digunakan untuk keuntungan yang lebih besar. Anda bisa mendapatkan 64k baris baru daripada nol jika Anda menambahkan,unblock cbs=1
di atas dan dari sana bisa menyuntikkan string sewenang-wenang per baris denganpaste
dan/dev/null
- tetapi dalam hal itu, jika tersedia untuk Anda, Anda mungkin sebaiknya menggunakan:Berikut ini beberapa
dd
contoh lagi:... yang menciptakan (atau memotong) sebuah
\0NUL
file yang diisi dengan direktori saat ini bernama H.txt ukuran 5000 bytes.dd
mencari langsung ke offset dan NUL-mengisi semua di belakangnya.... yang membuat file dengan nama dan ukuran yang sama tetapi diisi dengan karakter w. Ini mengambil keuntungan dari
dd
perilaku spesifik menulis setidaknya satu nol blok penuh jika terjadi kesalahan baca ketikanoerror
dansync
konversi ditentukan (dan - tanpacount=
- kemungkinan akan berlangsung lebih lama dari yang Anda inginkan) , dan dengan sengaja mengarahkan ulang deskriptor file writeonlydd
di stdin.sumber
The
%.0s
berarti untuk mengkonversi argumen sebagai tali , dengan presisi dari nol. Menurutman 3 printf
, nilai presisi dalam kasus seperti itu memberikarenanya ketika presisi adalah nol, argumen string tidak dicetak sama sekali. Namun
H
(yang merupakan bagian dari penentu format) akan dicetak sebanyak yang ada argumen, karena sesuai denganprintf
bagianman bash
sumber
Dalam hal ini,
%.0s
selalu cetak satu instance karakter sebelumnya, H dalam hal ini. Saat Anda menggunakan {1..5000}, shell memperluasnya dan itu menjadi:yaitu, perintah printf sekarang memiliki 5000 argumen, dan untuk setiap argumen, Anda akan mendapatkan satu H. Ini tidak harus berurutan atau numerik:
cetakan
HHHHH
- yaitu, jumlah argumen, 5 dalam hal ini.Catatan, elips pada contoh 1 di atas tidak dimasukkan secara harfiah, mereka ada di sana untuk menunjukkan urutan atau rentang.
sumber