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 \1akan menjadi referensi kembali.
Dengan :loopkami mendefinisikan label bernama loopdan dengan t loopitu 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 $fillerdari offset ${#string}dan seterusnya.
Lebar total output akan menjadi lebar maksimum $filleratau $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.
printfuntuk 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 %.20sformat 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.
echomendukung -e. printfhampir 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.
perl6mungkin memiliki cara untuk melakukannya dengan benar bahkan dengan karakter multi-byte. Tetapi di sisi lain perl6menjengkelkan 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 printfperintah 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 %.1syang =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 $strdan jika panjang $str<20, sisanya akan mengambil dari yang dihasilkan =untuk mengisi bukan spasi.