Jawaban:
Jawaban yang diperbarui menjadi solusi yang lebih umum. lihat juga jawaban saya yang lain di bawah ini hanya menggunakan ekspansi brace shell dan pritnf
.
$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:
Bagaimana itu bekerja?
ini (=*):$/
menangkap satu ruang, satu atau lebih =
yang diikuti oleh titik dua :
di akhir inputnya; kami menjadikan set =
sebagai pertandingan grup dan \1
akan menjadi referensi kembali.
Dengan :loop
kami mendefinisikan label bernama loop
dan dengan t loop
itu akan melompat ke label itu ketika s/ (=*):$/\1=:/
telah melakukan penggantian yang sukses;
Di bagian pengganti dengan \1=:
, itu akan selalu menambah jumlah =
s dan kembali usus besar itu sendiri ke akhir string.
filler='===================='
string='foo'
printf '%s\n' "$string${filler:${#string}}"
Memberi
foo=================
${#string}
adalah panjang dari nilai $string
, dan ${filler:${#string}}
merupakan substring dari $filler
dari offset ${#string}
dan seterusnya.
Lebar total output akan menjadi lebar maksimum $filler
atau $string
.
String pengisi dapat, pada sistem yang telah jot
, dibuat secara dinamis menggunakan
filler=$( jot -s '' -c 16 '=' '=' )
(untuk 16 =
baris). Sistem GNU dapat menggunakan seq
:
filler=$( seq -s '=' 1 16 | tr -dc '=' )
Sistem lain mungkin menggunakan Perl atau cara lain yang lebih cepat untuk membuat string secara dinamis.
printf
untuk menghasilkan filter yang hampir tersedia di semua sistem dan ekspansi penjepit dengan shell seperti bash/szh
?
printf
+ ekspansi brace bash
?
printf "%.20s:\n\n" "$str========================="
di mana %.20s
format pemotongan string
Salah satu cara untuk melakukannya:
printf "====================:\r%s\n\n" 'hello world!!'
====================\rhello world
, yang mungkin menjadi masalah jika OP perlu menyimpan ini dan tidak hanya mencetaknya ke layar.
echo -e '=================\rHello World!!'
, tetapi memiliki masalah yang sama dengan @terdon menunjuk itu.
echo
mendukung -e
. printf
hampir selalu lebih baik daripada echo
, karena berbagai alasan.
Pendekatan Perl:
$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======
Atau, lebih baik, @SatoKatsura tunjukkan dalam komentar:
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Jika Anda perlu mendukung karakter multi-byte UTF, gunakan:
PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Gagasan yang sama di shell:
v='hello world!!'; while [ ${#v} -lt 20 ]; do v="$v""="; done; printf '%s\n\n' "$v"
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
. Namun, ini (dan semua solusi lain yang diposting sejauh ini) rusak jika karakter multi-byte terlibat.
perl6
mungkin memiliki cara untuk melakukannya dengan benar bahkan dengan karakter multi-byte. Tetapi di sisi lain perl6
menjengkelkan dalam banyak hal.
PERL_UNICODE='AS'
. Misalnya: printf '%s' nóóös | perl -nle 'print length($_)'
mencetak 8 ("salah") saat printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'
mencetak 5 ("benar").
Cara lain adalah dengan hanya menggunakan printf
perintah dan menghasilkan pola karakter padding pertama dengan Shell Brace Expansion
(Anda dapat mengakhiri dengan angka ≥ area format yang ingin Anda cetak {1..end}
) dan dapatkan hanya setiap karakter pertama %.1s
yang =
s dan kemudian hanya mencetak panjang 20 karakter pertama daerah itu %.20s
. Ini semacam cara yang lebih baik untuk mengulangi karakter / kata daripada menduplikasinya.
printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:
Penjelasan:
Biasanya sebagai Brace Expansion , shell mengembang {1..20}
sebagai berikut jika kita mencetaknya.
printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Jadi dengan menambahkan tanda sama dengan itu ={1..20}
, shell akan berkembang sebagai berikut.
printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20
Dan dengan printf '%.1s'
yang sebenarnya berarti printf '%WIDE.LENGTH'
, kami mencetak hanya satu PANJANG dari yang di atas dengan 1
WIDE default . jadi akan menghasilkan =
s hanya dan 20 kali diulang sendiri.
Sekarang dengan printf '%.20s:\n'
kita mencetak hanya 20 panjang $str
dan jika panjang $str
<20, sisanya akan mengambil dari yang dihasilkan =
untuk mengisi bukan spasi.