Bagaimana saya bisa melakukan ini echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
ataupython -c 'print "=" * 100'
printf
bersama 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'
printf
bersama 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 =%.0s
yang artinya akan selalu mencetak satu pun, =
tidak peduli apa argumennya. Karena itu mencetak 100 =
s.
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 menyebabkan printf
kesalahan.
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
tr
adalah satu-satunya solusi POSIX karena seq
, yes
dan {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 " 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:
${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 perl
solusi.[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.awk
mengacu 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 1000
dantestrepeat 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 =; done
Menggunakan printf
builtin:
printf '=%.0s' {1..100}
Menentukan presisi di sini memotong string agar sesuai dengan lebar yang ditentukan ( 0
). Saat printf
menggunakan 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
/ tr
solusi, yang bekerja dengan baik bahkan dengan jumlah pengulangan yang tinggi (peringatan kecil: head -c
tidak kompatibel dengan POSIX, tetapi BSD dan GNU head
mengimplementasikannya); sementara dua solusi lainnya akan lambat dalam hal itu, mereka memiliki keuntungan bekerja dengan string multi- karakter juga.
yes
dan head
- 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 daripada head -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 untuk head
versi dan 0,675 untuk dd
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 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-f
dan -s
tampaknya 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
. seq
adalah untuk angka, bukan string. Lihat gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
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, GNU seq
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 tidak seq
akan 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 - paste
Metode ini berakhir pada baris baru. The tr
Metode tidak.
paste
tak terduga mengharuskan -d '\0'
untuk menentukan pembatas kosong, dan gagal dengan -d ''
- -d '\0'
harus bekerja dengan semua paste
implementasi 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 printf
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 .
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 echo
dan 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.
seq
bukan utilitas POSIX (meskipun BSD dan sistem Linux memiliki implementasi dari itu) - Anda dapat melakukan aritmatika shell POSIX dengan while
loop sebagai gantinya, seperti dalam jawaban @ Xennex81 (dengan printf "="
, seperti yang Anda sarankan dengan benar, daripada echo -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
:
echo -e ''$_{1..100}'\b='
Ini akan melakukan persis sama perl -E 'say "=" x 100'
tetapi dengan echo
hanya.
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 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 printf
cukup banyak menggunakan:
-v varname
: alih-alih mencetak ke output standar, printf
akan menempatkan konten string yang diformat dalam variabel varname
.printf
akan menggunakan argumen untuk mencetak jumlah spasi yang sesuai. Misalnya, printf '%*s' 42
akan mencetak 42 spasi.${var// /$pattern}
akan diperluas ke ekspansi var
dengan semua ruang diganti dengan ekspansi $pattern
.Anda juga dapat menyingkirkan tmp
variabel dalam repeat
fungsi 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}"
}
bash
operasi 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 = var
membutuhkan 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 substr
panggilan komplementer diperlukan untuk mengatasi bug di BSD awk
, di mana melewati nilai variabel yang dimulai dengan =
perintah break.)
NF = 100
solusi adalah sangat pintar (meskipun untuk mendapatkan 100 =
, Anda harus menggunakan NF = 101
). Peringatan adalah bahwa itu crash BSD awk
(tapi itu sangat cepat dengan gawk
dan bahkan lebih cepat dengan mawk
), dan bahwa dibahas POSIX tidak menugaskan untuk NF
, atau penggunaan bidang di BEGIN
blok. Anda dapat membuatnya bekerja di BSD awk
juga dengan sedikit perubahan: awk 'BEGIN { OFS = "="; $101=""; print }'
(tapi anehnya, di BSD awk
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 disarankan
awk NF=100 OFS='=' <<< ""
(menggunakan bash
dan gawk
)
Saya kira tujuan awal dari pertanyaan ini adalah untuk melakukan ini hanya dengan perintah bawaan shell. Jadi for
loop dan printf
s akan menjadi sah, sementara rep
, perl
dan juga jot
di 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-jot
akan 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}
seq
jot
seq
eval
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 b
output 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 echo
bukan 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 printf
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 untuk echo
. zsh melakukan ini. Dan pasti ada echo
s yang tidak mengenali -n
, karena itu bukan standar . (Banyak cangkang Bourne-style tidak menerima C-style untuk loop sama sekali, sehingga echo
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:
while ((n--)); do echo -n "$s"; done; echo
n
harus berupa variabel - cara ini tidak berfungsi dengan parameter posisi. $s
adalah teks yang harus diulang.
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 disukai echo
, setidaknya dalam penggunaan non-interaktif. Tetapi saya pikir itu sama sekali tidak pantas atau menyesatkan untuk memberikan echo
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.
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:
yes
perintah 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_char
urutan CSI ANSI.repeat_char
urutan 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========
length
tidak 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 tcsh
atau OpenBSD ksh
dan 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 =