tidak dengan gema, tetapi pada topik yang sama ruby -e 'puts "=" * 100'ataupython -c 'print "=" * 100'
Evgeny
1
Pertanyaan yang bagus Jawaban yang sangat bagus Saya telah menggunakan salah satu jawaban dalam pekerjaan nyata di sini, yang akan saya posting sebagai contoh: github.com/drbeco/oldfiles/blob/master/oldfiles (digunakan printfbersama seq)svrb=`printf '%.sv' $(seq $vrb)`
Dr Beco
Solusi umum untuk mencetak apa saja (1 atau lebih karakter, bahkan termasuk baris baru): Repeat_this () {i = 1; sementara ["$ i" -le "$ 2"]; lakukan printf "% s" "$ 1"; i = $ (($ i +1)); dilakukan; printf '\ n';}. Gunakan seperti ini: Repeat_ini "sesuatu" Number_of_repetitions. Misalnya, untuk menampilkan 5 kali sesuatu yang berulang termasuk 3 baris baru: Repeat_ini "$ (printf '\ n \ n \ nini')" 5. Hasil cetak akhir '\ n' dapat dihapus (tapi saya masukkan untuk membuat file teks, dan mereka membutuhkan baris baru sebagai karakter terakhir mereka!)
Olivier Dulac
Jawaban:
396
Kamu bisa memakai:
printf '=%.0s'{1..100}
Bagaimana ini bekerja:
Bash mengembang {1..100} sehingga perintahnya menjadi:
printf '=%.0s'1234...100
Saya telah mengatur format printf =%.0syang artinya akan selalu mencetak satu pun, =tidak peduli apa argumennya. Karena itu mencetak 100 =s.
Solusi hebat yang berkinerja cukup baik bahkan dengan jumlah pengulangan yang besar. Inilah pembungkus fungsi yang dapat Anda gunakan repl = 100, misalnya ( evaldiperlukan tipu daya, untuk mendasarkan ekspansi penjepit pada variabel):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
mklement0
7
Apakah mungkin untuk menetapkan batas atas menggunakan var? Saya sudah mencoba dan tidak berhasil.
Mike Purcell
70
Anda tidak dapat menggunakan variabel dalam ekspansi brace. Gunakan, seqmisalnya $(seq 1 $limit).
dogbane
11
Jika Anda memfungsikan ini, lebih baik atur ulang dari $s%.0sagar %.0s$standa hubung menyebabkan printfkesalahan.
KomodoDave
5
Ini membuat saya memperhatikan perilaku Bash printf: terus menerapkan format string hingga tidak ada argumen yang tersisa. Saya berasumsi itu memproses string format hanya sekali!
Jeenu
89
Tidak mudah. Tapi misalnya:
seq -s=100|tr -d '[:digit:]'
Atau mungkin cara yang sesuai standar:
printf %100s|tr " ""="
Ada juga a tput rep, tetapi untuk terminal saya di tangan (xterm dan linux) mereka tampaknya tidak mendukungnya :)
Perhatikan bahwa opsi pertama dengan seq mencetak satu kurang dari angka yang diberikan, sehingga contoh itu akan mencetak 99 =karakter.
Camilo Martin
13
printftradalah satu-satunya solusi POSIX karena seq, yesdan {1..3}bukan POSIX.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
Untuk mengulang string daripada hanya satu karakter: printf %100s | sed 's/ /abc/g'- output 'abcabcabc ...'
John Rix
3
+1 untuk tidak menggunakan loop dan hanya satu perintah eksternal ( tr). Anda juga dapat memperluasnya ke sesuatu seperti printf "%${COLUMNS}s\n" | tr " " "=".
musiphil
2
@ mklement0 Ya, saya berharap Anda menghitung baris baru terakhir karena kesalahan wc. Satu-satunya kesimpulan yang bisa saya ambil dari ini adalah " seqtidak boleh digunakan".
Catatan: Jawaban ini tidak menjawab pertanyaan awal, tetapi melengkapi jawaban yang ada dan bermanfaat dengan membandingkan kinerja .
Solusi dibandingkan dalam hal kecepatan eksekusi saja - persyaratan memori tidak diperhitungkan (mereka berbeda di seluruh solusi dan mungkin penting dengan jumlah pengulangan yang besar).
Ringkasan:
Jika jumlah pengulangan Anda kecil , katakan hingga sekitar 100, ada baiknya menggunakan solusi Bash-only , karena biaya startup dari utilitas eksternal penting, terutama Perl.
Namun, secara pragmatis, jika Anda hanya membutuhkan satu contoh karakter yang berulang, semua solusi yang ada mungkin baik-baik saja.
Dengan jumlah pengulangan yang besar , gunakan utilitas eksternal , karena akan jauh lebih cepat.
Secara khusus, hindari penggantian substring global Bash dengan string besar
(misalnya, ${var// /=}), karena sangat lambat.
Berikut ini adalah waktu yang diambil pada iMac akhir 2012 dengan CPU Intel Core i5 3,2 GHz dan Fusion Drive, menjalankan OSX 10.10.4 dan bash 3.2.57, dan merupakan rata-rata 1000 berjalan.
Entri adalah:
terdaftar dalam urutan durasi eksekusi (tercepat pertama)
diawali dengan:
M... solusi multi-karakter yang berpotensi
S... solusi tunggal -karakter-saja
P ... solusi yang sesuai dengan POSIX
diikuti oleh deskripsi singkat dari solusinya
diakhiri dengan nama penulis dari jawaban yang berasal
Solusi Bash-only memimpin paket - tetapi hanya dengan hitungan ulang sekecil ini! (Lihat di bawah).
Biaya permulaan utilitas eksternal memang penting di sini, terutama Perl. Jika Anda harus menyebutnya dalam satu lingkaran - dengan jumlah pengulangan kecil di setiap iterasi - hindari multi-utilitas awk,, dan perlsolusi.
Solusi Perl dari pertanyaan sejauh ini adalah yang tercepat.
Penggantian string global Bash ( ${foo// /=}) jelas-jelas sangat lambat dengan string besar, dan telah dikeluarkan dari menjalankan (butuh sekitar 50 menit (!) Di Bash 4.3.30, dan bahkan lebih lama di Bash 3.2.57 - Saya tidak pernah menunggu untuk sampai selesai).
Bash loop lambat, dan loop aritmatika ( (( i= 0; ... ))) lebih lambat daripada yang diperluas brace ( {1..n}) - meskipun loop aritmatika lebih hemat memori.
awkmengacu pada BSDawk (seperti juga ditemukan pada OSX) - ini terasa lebih lambat daripada gawk(GNU Awk) dan terutama mawk.
Perhatikan bahwa dengan jumlah besar dan multi-char. string, konsumsi memori dapat menjadi pertimbangan - pendekatan berbeda dalam hal itu.
Berikut skrip Bash ( testrepeat) yang menghasilkan hal di atas. Dibutuhkan 2 argumen:
jumlah pengulangan karakter
opsional, jumlah tes berjalan untuk melakukan dan menghitung waktu rata - rata dari
Dengan kata lain: timing di atas diperoleh dengan testrepeat 100 1000dantestrepeat 1000000 1000
#!/usr/bin/env bash
title(){ printf '%s:\t'"$1";}
TIMEFORMAT=$'%6Rs'# The number of repetitions of the input chars. to produce
COUNT_REPETITIONS=${1?Arguments:<charRepeatCount>[<testRunCount>]}# The number of test runs to perform to derive the average timing from.
COUNT_RUNS=${2:-1}# Discard the (stdout) output generated by default.# If you want to check the results, replace '/dev/null' on the following# line with a prefix path to which a running index starting with 1 will# be appended for each test run; e.g., outFilePrefix='outfile', which# will produce outfile1, outfile2, ...
outFilePrefix=/dev/null
{
outFile=$outFilePrefix
ndx=0
title '[M, P] printf %.s= [dogbane]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"# !! In order to use brace expansion with a variable, we must use `eval`.eval"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf '%.s=' {1..$COUNT_REPETITIONS} >"$outFile"
done"
title '[M ] echo -n - arithmetic loop [Eliah Kagan]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));dofor((i=0; i<COUNT_REPETITIONS;++i));do echo -n =;done>"$outFile"done
title '[M ] echo -n - brace expansion loop [eugene y]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"# !! In order to use brace expansion with a variable, we must use `eval`.eval"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
for i in {1..$COUNT_REPETITIONS}; do echo -n =; done >"$outFile"
done
"
title '[M ] printf + sed [user332325 (comment)]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
printf "%${COUNT_REPETITIONS}s"| sed 's/ /=/g'>"$outFile"done
title '[S ] printf + tr [user332325]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
printf "%${COUNT_REPETITIONS}s"| tr ' ''='>"$outFile"done
title '[S ] head + tr [eugene y]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
head -c $COUNT_REPETITIONS </dev/zero | tr '\0''='>"$outFile"done
title '[M ] seq -f [Sam Salisbury]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
seq -f '='-s '' $COUNT_REPETITIONS >"$outFile"done
title '[M ] jot -b [Stefan Ludwig]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
jot -s ''-b '=' $COUNT_REPETITIONS >"$outFile"done
title '[M ] yes + head + tr [Digital Trauma]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
yes =| head -$COUNT_REPETITIONS | tr -d '\n'>"$outFile"done
title '[M ] Perl [sid_com]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
perl -e "print \"=\" x $COUNT_REPETITIONS">"$outFile"done
title '[S, P] dd + tr [mklement0]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
dd if=/dev/zero bs=$COUNT_REPETITIONS count=12>/dev/null | tr '\0'"=">"$outFile"done# !! On OSX, awk is BSD awk, and mawk and gawk were installed later.# !! On Linux systems, awk may refer to either mawk or gawk.for awkBin in awk mawk gawk;doif[[-x $(command -v $awkBin)]];then
title "[M ] $awkBin"' - $(count+1)="=" [Steven Penny (variant)]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
$awkBin -v count=$COUNT_REPETITIONS 'BEGIN { OFS="="; $(count+1)=""; print }'>"$outFile"done
title "[M, P] $awkBin"' - while loop [Steven Penny]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"
time for(( n =0; n < COUNT_RUNS; n++));do
$awkBin -v count=$COUNT_REPETITIONS 'BEGIN { while (i++ < count) printf "=" }'>"$outFile"donefidone
title '[M ] printf + bash global substr. replacement [Tim]'[[ $outFile !='/dev/null']]&& outFile="$outFilePrefix$((++ndx))"# !! In Bash 4.3.30 a single run with repeat count of 1 million took almost# !! 50 *minutes*(!) to complete; n Bash 3.2.57 it's seemingly even slower -# !! didn't wait for it to finish.# !! Thus, this test is skipped for counts that are likely to be much slower# !! than the other tests.
skip=0[[ $BASH_VERSINFO -le 3&& COUNT_REPETITIONS -gt 1000]]&& skip=1[[ $BASH_VERSINFO -eq 4&& COUNT_REPETITIONS -gt 10000]]&& skip=1if(( skip ));then
echo 'n/a'>&2else
time for(( n =0; n < COUNT_RUNS; n++));do{ printf -v t "%${COUNT_REPETITIONS}s"'='; printf %s "${t// /=}";}>"$outFile"donefi}2>&1|
sort -t$'\t'-k2,2n|
awk -F $'\t'-v count=$COUNT_RUNS '{
printf "%s\t", $1;
if ($2 ~ "^n/a") { print $2 } else { printf "%.4f\n", $2 / count }}'|
column -s$'\t'-t
Sangat menarik untuk melihat perbandingan waktu, tetapi saya pikir dalam banyak program output buffer, jadi waktunya dapat diubah jika buffering dimatikan.
Sergiy Kolodyazhnyy
In order to use brace expansion with a variable, we must use `eval`👍
pyb
2
Jadi solusi perl (sid_com) pada dasarnya adalah yang tercepat ... setelah overhead awal peluncuran perl tercapai. (mulai dari 59ms untuk pengulangan kecil hingga 67ms untuk satu juta pengulangan ... jadi forking perl memerlukan sekitar 59ms pada sistem Anda)
Olivier Dulac
46
Ada lebih dari satu cara untuk melakukannya.
Menggunakan loop:
Ekspansi Brace dapat digunakan dengan literal integer:
for i in{1..100};do echo -n =;done
Lingkaran mirip-C memungkinkan penggunaan variabel:
Menentukan presisi di sini memotong string agar sesuai dengan lebar yang ditentukan ( 0). Saat printfmenggunakan kembali format string untuk menggunakan semua argumen, ini hanya mencetak "="100 kali.
++ untuk head/ trsolusi, yang bekerja dengan baik bahkan dengan jumlah pengulangan yang tinggi (peringatan kecil: head -ctidak kompatibel dengan POSIX, tetapi BSD dan GNU headmengimplementasikannya); sementara dua solusi lainnya akan lambat dalam hal itu, mereka memiliki keuntungan bekerja dengan string multi- karakter juga.
mklement0
1
Menggunakan yesdan head- berguna jika Anda ingin sejumlah baris: yes "" | head -n 100. trdapat membuatnya mencetak karakter apa pun:yes "" | head -n 100 | tr "\n" "="; echo
loxaxs
Agak mengherankan: dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/nullsecara signifikan lebih lambat daripada head -c100000000 < /dev/zero | tr '\0' '=' >/dev/nullversi. Tentu saja Anda harus menggunakan ukuran blok 100M + untuk mengukur perbedaan waktu secara wajar. 100M byte membutuhkan 1,7 s dan 1 s dengan dua versi masing-masing ditampilkan. Saya melepas tr dan hanya membuangnya ke /dev/nulldan mendapatkan 0,287 untuk headversi dan 0,675 untuk ddversi untuk satu miliar byte.
Ah, jadi saya menggunakan versi BSD dari seq yang ditemukan di OS X. Saya akan memperbarui jawabannya. Versi mana yang Anda gunakan?
Sam Salisbury
Saya menggunakan seq dari GNU coreutils.
John B
1
@JohnB: BSD seqsedang diputar ulang dengan cerdik di sini untuk mereplikasi string : string format dilewatkan ke -f- biasanya digunakan untuk memformat angka yang dihasilkan - hanya berisi string untuk direplikasi di sini sehingga output berisi salinan string itu saja. Sayangnya, GNU seqmenegaskan keberadaan format angka dalam string format, yang merupakan kesalahan yang Anda lihat.
mklement0
1
Bagus sekali; juga bekerja dengan string multi- karakter. Silakan gunakan "$1"(tanda kutip ganda), sehingga Anda juga dapat memasukkan karakter seperti '*'dan string dengan spasi kosong. Akhirnya, jika Anda ingin dapat menggunakan %, Anda harus menggandakannya (jika tidak seqakan berpikir itu bagian dari spesifikasi format seperti %f); menggunakan "${1//%/%%}"akan mengurus hal itu. Karena (seperti yang Anda sebutkan) Anda menggunakan BSDseq , ini akan bekerja pada OS mirip BSD secara umum (misalnya, FreeBSD) - sebaliknya, itu tidak akan bekerja di Linux , di mana GNUseq digunakan.
Bagus sekali; harap dicatat bahwa BSD secarapaste tak terduga mengharuskan -d '\0'untuk menentukan pembatas kosong, dan gagal dengan -d ''- -d '\0'harus bekerja dengan semua pasteimplementasi yang kompatibel dengan POSIX dan memang bekerja dengan GNUpaste juga.
mklement0
Mirip roh, dengan lebih sedikit alat tempel:yes | mapfile -n 100 -C 'printf = \#' -c 1
uskup
@ bishop: Walaupun perintah Anda memang membuat satu subkulit lebih sedikit, masih lebih lambat untuk jumlah pengulangan yang lebih tinggi, dan untuk jumlah pengulangan yang lebih rendah perbedaannya mungkin tidak masalah; ambang yang tepat mungkin bergantung pada perangkat keras dan OS, misalnya, pada mesin OSX 10.11.5 saya, jawaban ini sudah lebih cepat pada angka 500; coba time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1. Namun yang lebih penting: jika Anda printftetap menggunakan , Anda sebaiknya menggunakan pendekatan yang lebih sederhana dan lebih efisien dari jawaban yang diterima:printf '%.s=' $(seq 500)
mklement0
13
Tidak ada cara sederhana. Hindari penggunaan printfdan penggantian loop .
Bagus, tetapi hanya berkinerja cukup dengan jumlah pengulangan yang kecil. Inilah pembungkus fungsi yang dapat dipanggil sebagai repl = 100, misalnya (tidak menampilkan trailing \n):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
mklement0
1
@ mklement0 Senang Anda dapat menyediakan versi fungsi dari kedua solusi, memberi +1 pada keduanya!
Camilo Martin
8
Jika Anda ingin kepatuhan dan konsistensi POSIX di berbagai implementasi berbeda dari echodan printf, dan / atau shell selain dari hanya bash:
seq(){ n=$1;while[ $n -le $2 ];do echo $n; n=$((n+1));done;}# If you don't have it.
echo $(for each in $(seq 1100);do printf "=";done)
... akan menghasilkan output yang sama seperti perl -E 'say "=" x 100'di mana-mana.
Masalahnya adalah itu seqbukan utilitas POSIX (meskipun BSD dan sistem Linux memiliki implementasi dari itu) - Anda dapat melakukan aritmatika shell POSIX dengan whileloop sebagai gantinya, seperti dalam jawaban @ Xennex81 (dengan printf "=", seperti yang Anda sarankan dengan benar, daripada echo -n).
mklement0
1
Ups, Anda benar sekali. Hal-hal seperti itu baru saja melewati saya kadang-kadang karena standar itu tidak masuk akal. caladalah POSIX. seqtidak. Lagi pula, daripada menulis ulang jawaban dengan loop sementara (seperti yang Anda katakan, itu sudah ada di jawaban lain) saya akan menambahkan fungsi RYO. Lebih mendidik seperti itu ;-).
Geoff Nixon
8
Pertanyaannya adalah bagaimana melakukannya dengan echo:
echo -e ''$_{1..100}'\b='
Ini akan melakukan persis sama perl -E 'say "=" x 100'tetapi dengan echohanya.
Cara Bash murni tanpa eval, tanpa subkulit, tanpa alat eksternal, tanpa ekspansi penjepit (yaitu, Anda dapat meminta nomor untuk diulang dalam variabel):
Jika Anda diberi variabel nyang diperluas ke nomor (non-negatif) dan variabel pattern, misalnya,
Untuk trik kecil ini, kami printfcukup banyak menggunakan:
-v varname: alih-alih mencetak ke output standar, printfakan menempatkan konten string yang diformat dalam variabel varname.
'% * s': printfakan menggunakan argumen untuk mencetak jumlah spasi yang sesuai. Misalnya, printf '%*s' 42akan mencetak 42 spasi.
Akhirnya, ketika kita memiliki jumlah ruang yang diinginkan dalam variabel kita, kita menggunakan ekspansi parameter untuk mengganti semua ruang dengan pola kita: ${var// /$pattern}akan diperluas ke ekspansi vardengan semua ruang diganti dengan ekspansi $pattern.
Anda juga dapat menyingkirkan tmpvariabel dalam repeatfungsi dengan menggunakan ekspansi tidak langsung:
repeat(){# $1=number of patterns to repeat# $2=pattern# $3=output variable name
printf -v "$3"'%*s'"$1"
printf -v "$3"'%s'"${!3// /$2}"}
Variasi yang menarik untuk memasukkan nama variabel. Sementara solusi ini baik untuk jumlah pengulangan hingga sekitar 1.000 (dan dengan demikian mungkin baik untuk sebagian besar aplikasi kehidupan nyata, jika saya menebaknya), akan menjadi sangat lambat untuk jumlah yang lebih tinggi (lihat selanjutnya komentar).
mklement0
Tampaknya bashoperasi penggantian string global dalam konteks ekspansi parameter ( ${var//old/new}) sangat lambat: bash sangat lambat 3.2.57, dan lambat dalam bash 4.3.30, setidaknya pada sistem OSX 10.10.3 saya pada mesin 3.2 Ghz Intel Core i5: Dengan hitungan 1.000, semuanya lambat ( 3.2.57) / cepat ( 4.3.30): 0,1 / 0,004 detik. Meningkatkan hitungan ke 10.000 hasil angka yang sangat berbeda: repeat 10000 = varmembutuhkan sekitar 80 detik (!) Di bash 3.2.57, dan sekitar 0,3 detik di bash 4.3.30(jauh lebih cepat dari pada 3.2.57, tetapi masih lambat).
Bagus sekali; ini adalah POSIX-compliant dan cukup cepat bahkan dengan jumlah ulangan yang tinggi, sementara juga mendukung string multi-karakter. Berikut versi shell: awk 'BEGIN { while (c++ < 100) printf "=" }'. Dibungkus ke dalam fungsi shell parameter (Invoke sebagai repeat 100 =, misalnya): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }. (Dummy .prefix char dan substrpanggilan komplementer diperlukan untuk mengatasi bug di BSD awk, di mana melewati nilai variabel yang dimulai dengan =perintah break.)
mklement0
1
The NF = 100solusi adalah sangat pintar (meskipun untuk mendapatkan 100 =, Anda harus menggunakan NF = 101). Peringatan adalah bahwa itu crash BSD awk(tapi itu sangat cepat dengan gawkdan bahkan lebih cepat dengan mawk), dan bahwa dibahas POSIX tidak menugaskan untuk NF, atau penggunaan bidang di BEGINblok. Anda dapat membuatnya bekerja di BSD awkjuga dengan sedikit perubahan: awk 'BEGIN { OFS = "="; $101=""; print }'(tapi anehnya, di BSD awkitu tidak lebih cepat daripada solusi loop). Sebagai solusi shell parameter: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }.
mklement0
Catatan untuk pengguna - Trik NF = 100 menyebabkan kesalahan segmen pada awk yang lebih tua. Ini original-awkadalah nama di Linux dari awk yang lebih tua yang mirip dengan awk BSD, yang juga dilaporkan macet, jika Anda ingin mencoba ini. Perhatikan bahwa menabrak biasanya merupakan langkah pertama menuju menemukan bug yang dapat dieksploitasi. Jawaban ini sangat mempromosikan kode tidak aman.
2
Catatan untuk pengguna - original-awktidak standar dan tidak disarankan
Steven Penny
Alternatif untuk cuplikan kode pertama dapat awk NF=100 OFS='=' <<< ""(menggunakan bashdan gawk)
oliv
4
Saya kira tujuan awal dari pertanyaan ini adalah untuk melakukan ini hanya dengan perintah bawaan shell. Jadi forloop dan printfs akan menjadi sah, sementara rep, perldan juga jotdi bawah tidak. Tetap saja, perintah berikut
jot -s "/" -b "\\" $((COLUMNS/2))
misalnya, mencetak garis jendela selebar \/\/\/\/\/\/\/\/\/\/\/\/
Bagus sekali; ini bekerja dengan baik bahkan dengan jumlah ulangan yang tinggi (sementara juga mendukung string multi-karakter). Untuk lebih menggambarkan pendekatan, inilah setara dengan perintah OP: jot -s '' -b '=' 100. Peringatannya adalah bahwa sementara platform seperti BSD, termasuk OSX, datang dengan jot, distro Linux tidak .
mklement0
1
Terima kasih, saya suka penggunaan -s '' lebih baik. Saya telah mengubah skrip saya.
Stefan Ludwig
Pada sistem berbasis Debian baru-baru ini , apt install athena-jotakan menyediakan jot.
agc
4
Seperti yang dikatakan orang lain, dalam ekspansi bash brace mendahului ekspansi parameter , sehingga rentang hanya dapat berisi literal. dan memberikan solusi bersih tetapi tidak sepenuhnya portabel dari satu sistem ke sistem lain, bahkan jika Anda menggunakan shell yang sama pada masing-masing sistem. (Meskipun semakin tersedia; misalnya, dalam FreeBSD 9.3 dan lebih tinggi .) Dan bentuk-bentuk tipuan lainnya selalu bekerja tetapi agak tidak tepat.{m,n}seqjotseqeval
Untungnya, bash mendukung gaya-C untuk loop (dengan ekspresi aritmatika saja). Jadi, inilah cara "pesta murni" singkat:
Ini mengambil jumlah pengulangan sebagai argumen pertama dan string yang harus diulang (yang mungkin karakter tunggal, seperti dalam deskripsi masalah) sebagai argumen kedua. repecho 7 boutput bbbbbbb(diakhiri oleh baris baru).
Karena fokus di sini adalah pada mengulangi karakter tunggal dan shell adalah bash, itu mungkin aman untuk digunakan echobukan printf. Dan saya membaca deskripsi masalah dalam pertanyaan ini sebagai menyatakan preferensi untuk mencetak echo. Definisi fungsi di atas bekerja di bash dan ksh93 . Meskipun printflebih portabel (dan biasanya harus digunakan untuk hal semacam ini), echosintaksis bisa dibilang lebih mudah dibaca.
Beberapa shell yang echodibangun menafsirkan -dengan sendirinya sebagai pilihan - meskipun arti biasa -, menggunakan stdin untuk input, tidak masuk akal untuk echo. zsh melakukan ini. Dan pasti ada echos yang tidak mengenali -n, karena itu bukan standar . (Banyak cangkang Bourne-style tidak menerima C-style untuk loop sama sekali, sehingga echoperilaku mereka tidak perlu dipertimbangkan ..)
Di sini tugasnya adalah mencetak urutan; di sana , itu untuk menetapkannya ke variabel.
Jika $njumlah pengulangan yang diinginkan dan Anda tidak harus menggunakannya kembali, dan Anda ingin sesuatu yang lebih pendek:
while((n--));do echo -n "$s";done; echo
nharus berupa variabel - cara ini tidak berfungsi dengan parameter posisi. $sadalah teks yang harus diulang.
Sangat menghindari melakukan versi loop. printf "%100s" | tr ' ' '='optimal.
ocodo
Info latar belakang dan pujian yang bagus untuk mengemas fungsionalitas sebagai fungsi, yang juga berfungsi secara zshkebetulan. Pendekatan echo-in-a-loop bekerja dengan baik untuk jumlah pengulangan yang lebih kecil, tetapi untuk yang lebih besar ada alternatif yang sesuai dengan POSIX berdasarkan pada utilitas , sebagaimana dibuktikan oleh komentar @ Slomojo.
mklement0
Menambahkan tanda kurung di sekitar loop pendek Anda mempertahankan nilai n tanpa mempengaruhi (while ((n--)); do echo -n "$s"; done; echo)
gunakan printf alih-alih gema! itu jauh lebih portabel (gema -n hanya dapat bekerja pada beberapa sistem). lihat unix.stackexchange.com/questions/65803/… (salah satu jawaban Stephane Chazelas yang luar biasa)
Olivier Dulac
@OlivierDulac Pertanyaan di sini adalah tentang bash. Tidak masalah apa sistem operasi yang Anda jalankan, jika Anda menggunakan bash di atasnya , bash memiliki echobuiltin yang mendukung -n. Semangat dari apa yang Anda katakan benar-benar benar. printfharus hampir selalu lebih disukai echo, setidaknya dalam penggunaan non-interaktif. Tetapi saya pikir itu sama sekali tidak pantas atau menyesatkan untuk memberikan echojawaban atas pertanyaan yang menanyakannya dan yang memberikan informasi yang cukup untuk mengetahui bahwa itu akan berhasil . Harap dicatat juga bahwa dukungan untuk ((n--))(tanpa a $) itu sendiri tidak dijamin oleh POSIX.
Eliah Kagan
4
Python ada di mana-mana dan berfungsi sama di mana-mana.
Dengan terminal ANSI dan karakter US-ASCII untuk diulang. Anda dapat menggunakan urutan pelarian ANSI CSI. Ini adalah cara tercepat untuk mengulangi karakter.
lengthtidak akan bekerja expr, Anda mungkin bermaksud n=$(expr 10 - ${#vari}); Namun, itu lebih sederhana dan lebih efisien untuk menggunakan ekspansi aritmatika Bash: n=$(( 10 - ${#vari} )). Juga, inti dari jawaban Anda adalah pendekatan yang sangat Perl bahwa OP sedang mencari alternatif Bash .
mklement0
1
Ini adalah versi yang lebih panjang dari apa yang didukung oleh Eliah Kagan:
while[ $(( i--))-gt 0];do echo -n " ";done
Tentu saja Anda dapat menggunakan printf untuk itu juga, tetapi tidak terlalu sesuai dengan keinginan saya:
Jawaban saya sedikit lebih rumit, dan mungkin tidak sempurna, tetapi bagi mereka yang ingin menghasilkan angka besar, saya dapat melakukan sekitar 10 juta dalam 3 detik.
repeatString(){# argument 1: The string to print# argument 2: The number of times to print
stringToPrint=$1
length=$2
# Find the largest integer value of x in 2^x=(number of times to repeat) using logarithms
power=`echo "l(${length})/l(2)" | bc -l`
power=`echo "scale=0; ${power}/1" | bc`# Get the difference between the length and 2^x
diff=`echo "${length} - 2^${power}" | bc`# Double the string length to the power of xfor i in`seq "${power}"`;do
stringToPrint="${stringToPrint}${stringToPrint}"done#Since we know that the string is now at least bigger than half the total, grab however many more we need and add it to the string.
stringToPrint="${stringToPrint}${stringToPrint:0:${diff}}"
echo ${stringToPrint}}
Sebagian besar solusi yang ada semua bergantung pada {1..10}dukungan sintaksis dari shell, yang bash- dan zsh- spesifik, dan tidak berfungsi di tcshatau OpenBSD kshdan yang paling non-bash sh.
Berikut ini harus bekerja pada OS X dan semua sistem * BSD di shell apa pun; pada kenyataannya, ini dapat digunakan untuk menghasilkan seluruh matriks dari berbagai jenis ruang dekoratif:
ruby -e 'puts "=" * 100'
ataupython -c 'print "=" * 100'
printf
bersamaseq
)svrb=`printf '%.sv' $(seq $vrb)`
Jawaban:
Kamu bisa memakai:
Bagaimana ini bekerja:
Bash mengembang {1..100} sehingga perintahnya menjadi:
Saya telah mengatur format printf
=%.0s
yang artinya akan selalu mencetak satu pun,=
tidak peduli apa argumennya. Karena itu mencetak 100=
s.sumber
repl = 100
, misalnya (eval
diperlukan tipu daya, untuk mendasarkan ekspansi penjepit pada variabel):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
misalnya$(seq 1 $limit)
.$s%.0s
agar%.0s$s
tanda hubung menyebabkanprintf
kesalahan.printf
: terus menerapkan format string hingga tidak ada argumen yang tersisa. Saya berasumsi itu memproses string format hanya sekali!Tidak mudah. Tapi misalnya:
Atau mungkin cara yang sesuai standar:
Ada juga a
tput rep
, tetapi untuk terminal saya di tangan (xterm dan linux) mereka tampaknya tidak mendukungnya :)sumber
=
karakter.printf
tr
adalah satu-satunya solusi POSIX karenaseq
,yes
dan{1..3}
bukan POSIX.printf %100s | sed 's/ /abc/g'
- output 'abcabcabc ...'tr
). Anda juga dapat memperluasnya ke sesuatu sepertiprintf "%${COLUMNS}s\n" | tr " " "="
.wc
. Satu-satunya kesimpulan yang bisa saya ambil dari ini adalah "seq
tidak boleh digunakan".Ujung topi untuk @ gniourf_gniourf untuk masukannya.
Catatan: Jawaban ini tidak menjawab pertanyaan awal, tetapi melengkapi jawaban yang ada dan bermanfaat dengan membandingkan kinerja .
Solusi dibandingkan dalam hal kecepatan eksekusi saja - persyaratan memori tidak diperhitungkan (mereka berbeda di seluruh solusi dan mungkin penting dengan jumlah pengulangan yang besar).
Ringkasan:
(misalnya,
${var// /=}
), karena sangat lambat.Berikut ini adalah waktu yang diambil pada iMac akhir 2012 dengan CPU Intel Core i5 3,2 GHz dan Fusion Drive, menjalankan OSX 10.10.4 dan bash 3.2.57, dan merupakan rata-rata 1000 berjalan.
Entri adalah:
M
... solusi multi-karakter yang berpotensiS
... solusi tunggal -karakter-sajaP
... solusi yang sesuai dengan POSIXawk
,, danperl
solusi.${foo// /=}
) jelas-jelas sangat lambat dengan string besar, dan telah dikeluarkan dari menjalankan (butuh sekitar 50 menit (!) Di Bash 4.3.30, dan bahkan lebih lama di Bash 3.2.57 - Saya tidak pernah menunggu untuk sampai selesai).(( i= 0; ... ))
) lebih lambat daripada yang diperluas brace ({1..n}
) - meskipun loop aritmatika lebih hemat memori.awk
mengacu pada BSDawk
(seperti juga ditemukan pada OSX) - ini terasa lebih lambat daripadagawk
(GNU Awk) dan terutamamawk
.Berikut skrip Bash (
testrepeat
) yang menghasilkan hal di atas. Dibutuhkan 2 argumen:Dengan kata lain: timing di atas diperoleh dengan
testrepeat 100 1000
dantestrepeat 1000000 1000
sumber
In order to use brace expansion with a variable, we must use `eval`
👍Ada lebih dari satu cara untuk melakukannya.
Menggunakan loop:
Ekspansi Brace dapat digunakan dengan literal integer:
Lingkaran mirip-C memungkinkan penggunaan variabel:
Menggunakan
printf
builtin:Menentukan presisi di sini memotong string agar sesuai dengan lebar yang ditentukan (
0
). Saatprintf
menggunakan kembali format string untuk menggunakan semua argumen, ini hanya mencetak"="
100 kali.Menggunakan
head
(printf
, dll) dantr
:sumber
head
/tr
solusi, yang bekerja dengan baik bahkan dengan jumlah pengulangan yang tinggi (peringatan kecil:head -c
tidak kompatibel dengan POSIX, tetapi BSD dan GNUhead
mengimplementasikannya); sementara dua solusi lainnya akan lambat dalam hal itu, mereka memiliki keuntungan bekerja dengan string multi- karakter juga.yes
danhead
- berguna jika Anda ingin sejumlah baris:yes "" | head -n 100
.tr
dapat membuatnya mencetak karakter apa pun:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
secara signifikan lebih lambat daripadahead -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
versi. Tentu saja Anda harus menggunakan ukuran blok 100M + untuk mengukur perbedaan waktu secara wajar. 100M byte membutuhkan 1,7 s dan 1 s dengan dua versi masing-masing ditampilkan. Saya melepas tr dan hanya membuangnya ke/dev/null
dan mendapatkan 0,287 untukhead
versi dan 0,675 untukdd
versi untuk satu miliar byte.dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=>0,21332 s, 469 MB/s
; Untuk:dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=>0,161579 s, 619 MB/s
;Saya baru saja menemukan cara serius yang sangat mudah untuk melakukan ini menggunakan seq:
UPDATE: Ini berfungsi pada BSD
seq
yang datang dengan OS X. YMMV dengan versi lainAkan mencetak '#' 10 kali, seperti ini:
-f "#"
mengatur string format untuk mengabaikan angka dan hanya mencetak#
untuk masing-masing.-s ''
set pemisah ke string kosong untuk menghapus baris baru yang memasukkan seq antara setiap nomor-f
dan-s
tampaknya menjadi penting.EDIT: Ini dia dalam fungsi praktis ...
Yang bisa Anda panggil seperti ini ...
CATATAN: Jika Anda mengulangi
#
maka kutipan itu penting!sumber
seq: format ‘#’ has no % directive
.seq
adalah untuk angka, bukan string. Lihat gnu.org/software/coreutils/manual/html_node/seq-invocation.htmlseq
sedang diputar ulang dengan cerdik di sini untuk mereplikasi string : string format dilewatkan ke-f
- biasanya digunakan untuk memformat angka yang dihasilkan - hanya berisi string untuk direplikasi di sini sehingga output berisi salinan string itu saja. Sayangnya, GNUseq
menegaskan keberadaan format angka dalam string format, yang merupakan kesalahan yang Anda lihat."$1"
(tanda kutip ganda), sehingga Anda juga dapat memasukkan karakter seperti'*'
dan string dengan spasi kosong. Akhirnya, jika Anda ingin dapat menggunakan%
, Anda harus menggandakannya (jika tidakseq
akan berpikir itu bagian dari spesifikasi format seperti%f
); menggunakan"${1//%/%%}"
akan mengurus hal itu. Karena (seperti yang Anda sebutkan) Anda menggunakan BSDseq
, ini akan bekerja pada OS mirip BSD secara umum (misalnya, FreeBSD) - sebaliknya, itu tidak akan bekerja di Linux , di mana GNUseq
digunakan.Inilah dua cara menarik:
Perhatikan bahwa keduanya agak berbeda -
paste
Metode ini berakhir pada baris baru. Thetr
Metode tidak.sumber
paste
tak terduga mengharuskan-d '\0'
untuk menentukan pembatas kosong, dan gagal dengan-d ''
--d '\0'
harus bekerja dengan semuapaste
implementasi yang kompatibel dengan POSIX dan memang bekerja dengan GNUpaste
juga.yes | mapfile -n 100 -C 'printf = \#' -c 1
time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1
. Namun yang lebih penting: jika Andaprintf
tetap menggunakan , Anda sebaiknya menggunakan pendekatan yang lebih sederhana dan lebih efisien dari jawaban yang diterima:printf '%.s=' $(seq 500)
Tidak ada cara sederhana. Hindari penggunaan
printf
dan penggantian loop .sumber
repl = 100
, misalnya (tidak menampilkan trailing\n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Jika Anda ingin kepatuhan dan konsistensi POSIX di berbagai implementasi berbeda dari
echo
danprintf
, dan / atau shell selain dari hanyabash
:... akan menghasilkan output yang sama seperti
perl -E 'say "=" x 100'
di mana-mana.sumber
seq
bukan utilitas POSIX (meskipun BSD dan sistem Linux memiliki implementasi dari itu) - Anda dapat melakukan aritmatika shell POSIX denganwhile
loop sebagai gantinya, seperti dalam jawaban @ Xennex81 (denganprintf "="
, seperti yang Anda sarankan dengan benar, daripadaecho -n
).cal
adalah POSIX.seq
tidak. Lagi pula, daripada menulis ulang jawaban dengan loop sementara (seperti yang Anda katakan, itu sudah ada di jawaban lain) saya akan menambahkan fungsi RYO. Lebih mendidik seperti itu ;-).Pertanyaannya adalah bagaimana melakukannya dengan
echo
:Ini akan melakukan persis sama
perl -E 'say "=" x 100'
tetapi denganecho
hanya.sumber
$_1
,,$_2
atau yang lain dari seratus variabel memiliki nilai.Cara Bash murni tanpa
eval
, tanpa subkulit, tanpa alat eksternal, tanpa ekspansi penjepit (yaitu, Anda dapat meminta nomor untuk diulang dalam variabel):Jika Anda diberi variabel
n
yang diperluas ke nomor (non-negatif) dan variabelpattern
, misalnya,Anda dapat membuat fungsi dengan ini:
Dengan set ini:
Untuk trik kecil ini, kami
printf
cukup banyak menggunakan:-v varname
: alih-alih mencetak ke output standar,printf
akan menempatkan konten string yang diformat dalam variabelvarname
.printf
akan menggunakan argumen untuk mencetak jumlah spasi yang sesuai. Misalnya,printf '%*s' 42
akan mencetak 42 spasi.${var// /$pattern}
akan diperluas ke ekspansivar
dengan semua ruang diganti dengan ekspansi$pattern
.Anda juga dapat menyingkirkan
tmp
variabel dalamrepeat
fungsi dengan menggunakan ekspansi tidak langsung:sumber
bash
operasi penggantian string global dalam konteks ekspansi parameter (${var//old/new}
) sangat lambat: bash sangat lambat3.2.57
, dan lambat dalam bash4.3.30
, setidaknya pada sistem OSX 10.10.3 saya pada mesin 3.2 Ghz Intel Core i5: Dengan hitungan 1.000, semuanya lambat (3.2.57
) / cepat (4.3.30
): 0,1 / 0,004 detik. Meningkatkan hitungan ke 10.000 hasil angka yang sangat berbeda:repeat 10000 = var
membutuhkan sekitar 80 detik (!) Di bash3.2.57
, dan sekitar 0,3 detik di bash4.3.30
(jauh lebih cepat dari pada3.2.57
, tetapi masih lambat).Atau
Contoh
sumber
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Dibungkus ke dalam fungsi shell parameter (Invoke sebagairepeat 100 =
, misalnya):repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Dummy.
prefix char dansubstr
panggilan komplementer diperlukan untuk mengatasi bug di BSDawk
, di mana melewati nilai variabel yang dimulai dengan=
perintah break.)NF = 100
solusi adalah sangat pintar (meskipun untuk mendapatkan 100=
, Anda harus menggunakanNF = 101
). Peringatan adalah bahwa itu crash BSDawk
(tapi itu sangat cepat dengangawk
dan bahkan lebih cepat denganmawk
), dan bahwa dibahas POSIX tidak menugaskan untukNF
, atau penggunaan bidang diBEGIN
blok. Anda dapat membuatnya bekerja di BSDawk
juga dengan sedikit perubahan:awk 'BEGIN { OFS = "="; $101=""; print }'
(tapi anehnya, di BSDawk
itu tidak lebih cepat daripada solusi loop). Sebagai solusi shell parameter:repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.original-awk
adalah nama di Linux dari awk yang lebih tua yang mirip dengan awk BSD, yang juga dilaporkan macet, jika Anda ingin mencoba ini. Perhatikan bahwa menabrak biasanya merupakan langkah pertama menuju menemukan bug yang dapat dieksploitasi. Jawaban ini sangat mempromosikan kode tidak aman.original-awk
tidak standar dan tidak disarankanawk NF=100 OFS='=' <<< ""
(menggunakanbash
dangawk
)Saya kira tujuan awal dari pertanyaan ini adalah untuk melakukan ini hanya dengan perintah bawaan shell. Jadi
for
loop danprintf
s akan menjadi sah, sementararep
,perl
dan jugajot
di bawah tidak. Tetap saja, perintah berikutjot -s "/" -b "\\" $((COLUMNS/2))
misalnya, mencetak garis jendela selebar
\/\/\/\/\/\/\/\/\/\/\/\/
sumber
jot -s '' -b '=' 100
. Peringatannya adalah bahwa sementara platform seperti BSD, termasuk OSX, datang denganjot
, distro Linux tidak .apt install athena-jot
akan menyediakanjot
.Seperti yang dikatakan orang lain, dalam ekspansi bash brace mendahului ekspansi parameter , sehingga rentang hanya dapat berisi literal. dan memberikan solusi bersih tetapi tidak sepenuhnya portabel dari satu sistem ke sistem lain, bahkan jika Anda menggunakan shell yang sama pada masing-masing sistem. (Meskipun semakin tersedia; misalnya, dalam FreeBSD 9.3 dan lebih tinggi .) Dan bentuk-bentuk tipuan lainnya selalu bekerja tetapi agak tidak tepat.
{m,n}
seq
jot
seq
eval
Untungnya, bash mendukung gaya-C untuk loop (dengan ekspresi aritmatika saja). Jadi, inilah cara "pesta murni" singkat:
Ini mengambil jumlah pengulangan sebagai argumen pertama dan string yang harus diulang (yang mungkin karakter tunggal, seperti dalam deskripsi masalah) sebagai argumen kedua.
repecho 7 b
outputbbbbbbb
(diakhiri oleh baris baru).Dennis Williamson pada dasarnya memberikan solusi ini empat tahun lalu dalam jawaban yang sangat baik untuk Membuat serangkaian karakter berulang dalam skrip shell . Badan fungsi saya sedikit berbeda dari kode di sana:
Karena fokus di sini adalah pada mengulangi karakter tunggal dan shell adalah bash, itu mungkin aman untuk digunakan
echo
bukanprintf
. Dan saya membaca deskripsi masalah dalam pertanyaan ini sebagai menyatakan preferensi untuk mencetakecho
. Definisi fungsi di atas bekerja di bash dan ksh93 . Meskipunprintf
lebih portabel (dan biasanya harus digunakan untuk hal semacam ini),echo
sintaksis bisa dibilang lebih mudah dibaca.Beberapa shell yang
echo
dibangun menafsirkan-
dengan sendirinya sebagai pilihan - meskipun arti biasa-
, menggunakan stdin untuk input, tidak masuk akal untukecho
. zsh melakukan ini. Dan pasti adaecho
s yang tidak mengenali-n
, karena itu bukan standar . (Banyak cangkang Bourne-style tidak menerima C-style untuk loop sama sekali, sehinggaecho
perilaku mereka tidak perlu dipertimbangkan ..)Di sini tugasnya adalah mencetak urutan; di sana , itu untuk menetapkannya ke variabel.
Jika
$n
jumlah pengulangan yang diinginkan dan Anda tidak harus menggunakannya kembali, dan Anda ingin sesuatu yang lebih pendek:n
harus berupa variabel - cara ini tidak berfungsi dengan parameter posisi.$s
adalah teks yang harus diulang.sumber
printf "%100s" | tr ' ' '='
optimal.zsh
kebetulan. Pendekatan echo-in-a-loop bekerja dengan baik untuk jumlah pengulangan yang lebih kecil, tetapi untuk yang lebih besar ada alternatif yang sesuai dengan POSIX berdasarkan pada utilitas , sebagaimana dibuktikan oleh komentar @ Slomojo.(while ((n--)); do echo -n "$s"; done; echo)
echo
builtin yang mendukung-n
. Semangat dari apa yang Anda katakan benar-benar benar.printf
harus hampir selalu lebih disukaiecho
, setidaknya dalam penggunaan non-interaktif. Tetapi saya pikir itu sama sekali tidak pantas atau menyesatkan untuk memberikanecho
jawaban atas pertanyaan yang menanyakannya dan yang memberikan informasi yang cukup untuk mengetahui bahwa itu akan berhasil . Harap dicatat juga bahwa dukungan untuk((n--))
(tanpa a$
) itu sendiri tidak dijamin oleh POSIX.Python ada di mana-mana dan berfungsi sama di mana-mana.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Karakter dan jumlah dilewatkan sebagai parameter terpisah.
sumber
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Di bash 3.0 atau lebih tinggi
sumber
Berarti lain untuk mengulang string sewenang-wenang n kali:
Pro:
Cons:
yes
perintah Gnu Core Utils .Dengan terminal ANSI dan karakter US-ASCII untuk diulang. Anda dapat menggunakan urutan pelarian ANSI CSI. Ini adalah cara tercepat untuk mengulangi karakter.
Atau secara statis:
Cetak garis 80 kali
=
:printf '=\e[80b\n'
Keterbatasan:
repeat_char
urutan CSI ANSI.repeat_char
urutan CSI ANSI ke karakter yang diulang.sumber
Inilah yang saya gunakan untuk mencetak garis karakter di layar di linux (berdasarkan terminal / lebar layar)
Cetak "=" di layar:
Penjelasan:
Cetak tanda sama dengan urutan yang diberikan:
Gunakan output dari sebuah perintah (ini adalah fitur bash yang disebut Substitusi Perintah):
Berikan urutan, saya telah menggunakan 1 hingga 20 sebagai contoh. Pada perintah terakhir, perintah tput digunakan sebagai ganti 20:
Berikan jumlah kolom yang saat ini digunakan di terminal:
sumber
sumber
sumber
Paling sederhana adalah menggunakan one-liner ini di csh / tcsh:
sumber
Alternatif yang lebih elegan untuk solusi Python yang diusulkan adalah:
sumber
Jika Anda ingin mengulang karakter n kali menjadi na VARIABEL kali tergantung pada, katakanlah, panjang string yang dapat Anda lakukan:
Ini menampilkan:
sumber
length
tidak akan bekerjaexpr
, Anda mungkin bermaksudn=$(expr 10 - ${#vari})
; Namun, itu lebih sederhana dan lebih efisien untuk menggunakan ekspansi aritmatika Bash:n=$(( 10 - ${#vari} ))
. Juga, inti dari jawaban Anda adalah pendekatan yang sangat Perl bahwa OP sedang mencari alternatif Bash .Ini adalah versi yang lebih panjang dari apa yang didukung oleh Eliah Kagan:
Tentu saja Anda dapat menggunakan printf untuk itu juga, tetapi tidak terlalu sesuai dengan keinginan saya:
Versi ini kompatibel dengan Dash:
dengan saya menjadi nomor awal.
sumber
while (( i-- )); do echo -n " "; done
berfungsi positif .Sampel berjalan
Referensi lib di: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
sumber
Anda dapat melakukan ini dengan
echo
jikaecho
diikuti olehsed
:Sebenarnya, itu
echo
tidak perlu di sana.sumber
Jawaban saya sedikit lebih rumit, dan mungkin tidak sempurna, tetapi bagi mereka yang ingin menghasilkan angka besar, saya dapat melakukan sekitar 10 juta dalam 3 detik.
sumber
Paling sederhana adalah menggunakan one-liner ini di bash:
sumber
Pilihan lain adalah menggunakan GNU seq dan menghapus semua angka dan baris baru yang dihasilkannya:
Perintah ini mencetak
#
karakter 100 kali.sumber
Sebagian besar solusi yang ada semua bergantung pada
{1..10}
dukungan sintaksis dari shell, yangbash
- danzsh
- spesifik, dan tidak berfungsi ditcsh
atau OpenBSDksh
dan yang paling non-bashsh
.Berikut ini harus bekerja pada OS X dan semua sistem * BSD di shell apa pun; pada kenyataannya, ini dapat digunakan untuk menghasilkan seluruh matriks dari berbagai jenis ruang dekoratif:
Sedihnya, kami tidak mendapatkan baris baru; yang dapat diperbaiki dengan tambahan
printf '\n'
setelah flip:Referensi:
sumber
Proposal saya (menerima nilai variabel untuk n):
sumber