Câu trả lời:
Cập nhật câu trả lời để được giải pháp tổng quát hơn. xem thêm câu trả lời khác của tôi dưới đây chỉ sử dụng mở rộng nẹp vỏ và pritnf
.
$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:
Làm thế nào nó hoạt động?
cái này (=*):$/
ghi lại một khoảng trắng, một hoặc nhiều hơn =
theo sau là dấu hai chấm :
ở cuối đầu vào của nó; chúng tôi thực hiện tập hợp =
như một trận đấu nhóm và\1
sẽ là tài liệu tham khảo ngược.
Với :loop
chúng tôi đã xác định một nhãn có tên loop
và với t loop
nó sẽ nhảy đến nhãn đó khi mộts/ (=*):$/\1=:/
thay thế thành công;
Trong phần thay thế bằng \1=:
, nó sẽ luôn tăng số =
s và đặt lại dấu hai chấm vào cuối chuỗi.
filler='===================='
string='foo'
printf '%s\n' "$string${filler:${#string}}"
Tặng
foo=================
${#string}
là độ dài của giá trị $string
và ${filler:${#string}}
là chuỗi con của $filler
offset${#string}
trở đi.
Tổng chiều rộng của đầu ra sẽ là chiều rộng tối đa của $filler
hoặc$string
.
Chuỗi filler có thể, trên các hệ thống đã jot
được tạo động bằng cách sử dụng
filler=$( jot -s '' -c 16 '=' '=' )
(cho 16 =
trong một dòng). Các hệ thống GNU có thể sử dụng seq
:
filler=$( seq -s '=' 1 16 | tr -dc '=' )
Các hệ thống khác có thể sử dụng Perl hoặc một số cách nhanh hơn khác để tạo chuỗi động.
printf
để tạo bộ lọc gần như có sẵn trong tất cả các hệ thống và mở rộng dấu ngoặc với vỏ như thế bash/szh
nào?
printf
+ mở rộng cú đúp trong bash
?
printf "%.20s:\n\n" "$str========================="
%.20s
định dạng cắt chuỗi ở đâu
Một cách để làm điều đó:
printf "====================:\r%s\n\n" 'hello world!!'
====================\rhello world
, đây có thể là một vấn đề nếu OP cần lưu trữ cái này và không chỉ in nó ra màn hình.
echo -e '=================\rHello World!!'
, nhưng có vấn đề tương tự như @terdon chỉ ra rằng.
echo
hỗ trợ -e
. printf
hầu như luôn luôn tốt hơn echo
, vì nhiều lý do.
Một cách tiếp cận Perl:
$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======
Hoặc, tốt hơn, @SatoKatsura chỉ ra trong các ý kiến:
perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Nếu bạn cần hỗ trợ các ký tự nhiều byte UTF, hãy sử dụng:
PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'
Cùng một ý tưởng trong vỏ:
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"'
. Tuy nhiên, điều này (và tất cả các giải pháp khác được đăng cho đến nay) sẽ phá vỡ nếu các ký tự nhiều byte có liên quan.
perl6
có thể có một cách để làm điều đó một cách chính xác ngay cả với các ký tự nhiều byte. Nhưng mặt khác lại perl6
gây phiền nhiễu theo nhiều cách.
PERL_UNICODE='AS'
. Ví dụ: printf '%s' nóóös | perl -nle 'print length($_)'
in 8 ("sai") trong khi printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'
in 5 ("đúng").
Một cách khác là chỉ sử dụng printf
lệnh và tạo mẫu đệm ký tự trước Shell Brace Expansion
(Bạn có thể kết thúc bằng một khu vực định dạng số bạn muốn in {1..end}
) và chỉ nhận mỗi ký tự đầu tiên của nó %.1s
, =
sau đó chỉ in 20 ký tự đầu tiên diện tích đó %.20s
. Đây là cách tốt hơn để có các ký tự / từ lặp đi lặp lại thay vì sao chép chúng.
printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:
Giải thích:
Thông thường như Brace Expansion , shell mở rộng {1..20}
như sau nếu chúng ta in chúng.
printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Vì vậy, với việc thêm một dấu bằng cho nó ={1..20}
, shell sẽ mở rộng như sau.
printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20
Và với printf '%.1s'
ý nghĩa thực sự printf '%WIDE.LENGTH'
, chúng tôi chỉ in một LENGTH của những người ở trên với WIDE mặc định1
. vì vậy sẽ có kết quả=
s và 20 lần lặp lại chính nó.
Bây giờ với printf '%.20s:\n'
chúng tôi chỉ in 20 độ dài $str
và nếu chiều dài $str
<20, phần còn lại sẽ lấy từ =
s được tạo để điền vào thay vì khoảng trắng.