Bagaimana saya bisa melakukan ini echo?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'ataupython -c 'print "=" * 100'
printfbersama seq)svrb=`printf '%.sv' $(seq $vrb)`
Bagaimana saya bisa melakukan ini echo?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'ataupython -c 'print "=" * 100'
printfbersama seq)svrb=`printf '%.sv' $(seq $vrb)`
Jawaban:
Kamu bisa memakai:
printf '=%.0s' {1..100}
Bagaimana ini bekerja:
Bash mengembang {1..100} sehingga perintahnya menjadi:
printf '=%.0s' 1 2 3 4 ... 100
Saya telah mengatur format printf =%.0syang artinya akan selalu mencetak satu pun, =tidak peduli apa argumennya. Karena itu mencetak 100 =s.
repl = 100, misalnya ( evaldiperlukan tipu daya, untuk mendasarkan ekspansi penjepit pada variabel):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seqmisalnya $(seq 1 $limit).
$s%.0sagar %.0s$standa hubung menyebabkan printfkesalahan.
printf: terus menerapkan format string hingga tidak ada argumen yang tersisa. Saya berasumsi itu memproses string format hanya sekali!
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 :)
=karakter.
printf tradalah satu-satunya solusi POSIX karena seq, yesdan {1..3}bukan POSIX.
printf %100s | sed 's/ /abc/g'- output 'abcabcabc ...'
tr). Anda juga dapat memperluasnya ke sesuatu seperti printf "%${COLUMNS}s\n" | tr " " "=".
wc. Satu-satunya kesimpulan yang bisa saya ambil dari ini adalah " seqtidak 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:
${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 POSIX[M, P] printf %.s= [dogbane]: 0.0002
[M ] printf + bash global substr. replacement [Tim]: 0.0005
[M ] echo -n - brace expansion loop [eugene y]: 0.0007
[M ] echo -n - arithmetic loop [Eliah Kagan]: 0.0013
[M ] seq -f [Sam Salisbury]: 0.0016
[M ] jot -b [Stefan Ludwig]: 0.0016
[M ] awk - $(count+1)="=" [Steven Penny (variant)]: 0.0019
[M, P] awk - while loop [Steven Penny]: 0.0019
[S ] printf + tr [user332325]: 0.0021
[S ] head + tr [eugene y]: 0.0021
[S, P] dd + tr [mklement0]: 0.0021
[M ] printf + sed [user332325 (comment)]: 0.0021
[M ] mawk - $(count+1)="=" [Steven Penny (variant)]: 0.0025
[M, P] mawk - while loop [Steven Penny]: 0.0026
[M ] gawk - $(count+1)="=" [Steven Penny (variant)]: 0.0028
[M, P] gawk - while loop [Steven Penny]: 0.0028
[M ] yes + head + tr [Digital Trauma]: 0.0029
[M ] Perl [sid_com]: 0.0059
awk,, dan perlsolusi.[M ] Perl [sid_com]: 0.0067
[M ] mawk - $(count+1)="=" [Steven Penny (variant)]: 0.0254
[M ] gawk - $(count+1)="=" [Steven Penny (variant)]: 0.0599
[S ] head + tr [eugene y]: 0.1143
[S, P] dd + tr [mklement0]: 0.1144
[S ] printf + tr [user332325]: 0.1164
[M, P] mawk - while loop [Steven Penny]: 0.1434
[M ] seq -f [Sam Salisbury]: 0.1452
[M ] jot -b [Stefan Ludwig]: 0.1690
[M ] printf + sed [user332325 (comment)]: 0.1735
[M ] yes + head + tr [Digital Trauma]: 0.1883
[M, P] gawk - while loop [Steven Penny]: 0.2493
[M ] awk - $(count+1)="=" [Steven Penny (variant)]: 0.2614
[M, P] awk - while loop [Steven Penny]: 0.3211
[M, P] printf %.s= [dogbane]: 2.4565
[M ] echo -n - brace expansion loop [eugene y]: 7.5877
[M ] echo -n - arithmetic loop [Eliah Kagan]: 13.5426
[M ] printf + bash global substr. replacement [Tim]: n/a
${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.awkmengacu pada BSD awk (seperti juga ditemukan pada OSX) - ini terasa lebih lambat daripada gawk(GNU Awk) dan terutama mawk.Berikut skrip Bash ( testrepeat) yang menghasilkan hal di atas. Dibutuhkan 2 argumen:
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++ )); do
for ((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=1 2>/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; do
if [[ -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"
done
fi
done
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=1
if (( skip )); then
echo 'n/a' >&2
else
time for (( n = 0; n < COUNT_RUNS; n++ )); do
{ printf -v t "%${COUNT_REPETITIONS}s" '='; printf %s "${t// /=}"; } >"$outFile"
done
fi
} 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
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:
for i in {1..100}; do echo -n =; done Lingkaran mirip-C memungkinkan penggunaan variabel:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; doneMenggunakan printfbuiltin:
printf '=%.0s' {1..100}
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.
Menggunakan head( printf, dll) dan tr:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
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.
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
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.
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 seqyang datang dengan OS X. YMMV dengan versi lain
seq -f "#" -s '' 10
Akan 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-fdan -stampaknya menjadi penting.EDIT: Ini dia dalam fungsi praktis ...
repeat () {
seq -f $1 -s '' $2; echo
}
Yang bisa Anda panggil seperti ini ...
repeat "#" 10
CATATAN: Jika Anda mengulangi #maka kutipan itu penting!
seq: format ‘#’ has no % directive. seqadalah untuk angka, bukan string. Lihat gnu.org/software/coreutils/manual/html_node/seq-invocation.html
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.
"$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 BSD seq , ini akan bekerja pada OS mirip BSD secara umum (misalnya, FreeBSD) - sebaliknya, itu tidak akan bekerja di Linux , di mana GNU seq digunakan.
Inilah dua cara menarik:
ubuntu @ ubuntu: ~ $ yes = | kepala -10 | tempel -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | kepala -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Perhatikan bahwa keduanya agak berbeda - pasteMetode ini berakhir pada baris baru. The trMetode tidak.
paste 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 GNU paste 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 Anda printftetap 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 printfdan penggantian loop .
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
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 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 1 100); do printf "="; done)
... akan menghasilkan output yang sama seperti perl -E 'say "=" x 100'di mana-mana.
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).
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 ;-).
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,
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Anda dapat membuat fungsi dengan ini:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
local tmp
printf -v tmp '%*s' "$1"
printf -v "$3" '%s' "${tmp// /$2}"
}
Dengan set ini:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
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.printfakan menggunakan argumen untuk mencetak jumlah spasi yang sesuai. Misalnya, printf '%*s' 42akan mencetak 42 spasi.${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}"
}
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).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Atau
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
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.)
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 }'; }.
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.
original-awktidak standar dan tidak disarankan
awk NF=100 OFS='=' <<< ""(menggunakan bashdan gawk)
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 \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100. Peringatannya adalah bahwa sementara platform seperti BSD, termasuk OSX, datang dengan jot, distro Linux tidak .
apt install athena-jotakan menyediakan jot.
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:
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
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).
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 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.
printf "%100s" | tr ' ' '='optimal.
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.
(while ((n--)); do echo -n "$s"; done; echo)
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.
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.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Di bash 3.0 atau lebih tinggi
for i in {1..100};do echo -n =;done
Berarti lain untuk mengulang string sewenang-wenang n kali:
Pro:
Cons:
yesperintah Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Dengan terminal ANSI dan karakter US-ASCII untuk diulang. Anda dapat menggunakan urutan pelarian ANSI CSI. Ini adalah cara tercepat untuk mengulangi karakter.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Atau secara statis:
Cetak garis 80 kali =:
printf '=\e[80b\n'
Keterbatasan:
repeat_charurutan CSI ANSI.repeat_charurutan CSI ANSI ke karakter yang diulang.Inilah yang saya gunakan untuk mencetak garis karakter di layar di linux (berdasarkan terminal / lebar layar)
printf '=%.0s' $(seq 1 $(tput cols))
Penjelasan:
Cetak tanda sama dengan urutan yang diberikan:
printf '=%.0s' #sequence
Gunakan output dari sebuah perintah (ini adalah fitur bash yang disebut Substitusi Perintah):
$(example_command)
Berikan urutan, saya telah menggunakan 1 hingga 20 sebagai contoh. Pada perintah terakhir, perintah tput digunakan sebagai ganti 20:
seq 1 20
Berikan jumlah kolom yang saat ini digunakan di terminal:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Paling sederhana adalah menggunakan one-liner ini di csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Alternatif yang lebih elegan untuk solusi Python yang diusulkan adalah:
python -c 'print "="*(1000)'
Jika Anda ingin mengulang karakter n kali menjadi na VARIABEL kali tergantung pada, katakanlah, panjang string yang dapat Anda lakukan:
#!/bin/bash
vari='AB'
n=$(expr 10 - length $vari)
echo 'vari equals.............................: '$vari
echo 'Up to 10 positions I must fill with.....: '$n' equal signs'
echo $vari$(perl -E 'say "=" x '$n)
Ini menampilkan:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
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 .
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:
printf "%$(( i*2 ))s"
Versi ini kompatibel dengan Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
dengan saya menjadi nomor awal.
function repeatString()
{
local -r string="${1}"
local -r numberToRepeat="${2}"
if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
then
local -r result="$(printf "%${numberToRepeat}s")"
echo -e "${result// /${string}}"
fi
}
Sampel berjalan
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Referensi lib di: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
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 x
for 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}
}
Paling sederhana adalah menggunakan one-liner ini di bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
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:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Sedihnya, kami tidak mendapatkan baris baru; yang dapat diperbaiki dengan tambahan printf '\n'setelah flip:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Referensi:
Proposal saya (menerima nilai variabel untuk n):
n=100
seq 1 $n | xargs -I {} printf =