Đệm khoảng trắng dấu cách trong một chuỗi với một ký tự khác


12

Tôi muốn xuất hello worldhơn 20 ký tự.

printf "%-20s :\n\n" 'hello world!!'

# Actual output
hello world!!        :

# Wanted output
hello world!!========:

Tuy nhiên, tôi không muốn hoàn thành với khoảng trắng mà thay vào đó là " = ". Làm thế nào để làm điều đó?

Câu trả lời:


9

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 :loopchúng tôi đã xác định một nhãn có tên loopvà với t loopnó 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.


1
Vì vậy, bạn phải điều chỉnh cờ tùy thuộc vào bao nhiêu từ đầu vào?
dùng1686

@grawity Tôi đã cập nhật câu trả lời của tôi cho giải pháp chung bây giờ.
asнι

20
filler='===================='
string='foo'

printf '%s\n' "$string${filler:${#string}}"

Tặng

foo=================

${#string}là độ dài của giá trị $string${filler:${#string}}là chuỗi con của $filleroffset${#string} trở đi.

Tổng chiều rộng của đầu ra sẽ là chiều rộng tối đa của $fillerhoặ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.


Tại sao không sử dụ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/szhnào?
αғsнιη

@sddgob Bạn sẽ làm thế nào với printf+ mở rộng cú đúp trong bash?
Kusalananda


17
printf "%.20s:\n\n" "$str========================="

%.20sđịnh dạng cắt chuỗi ở đâu


2
Đây là IMHO, một giải pháp tốt hơn của tôi. Nó chỉ cần một lời giải thích ngắn về chuỗi định dạng.
Kusalananda

12

Một cách để làm điều đó:

printf "====================:\r%s\n\n" 'hello world!!'

6
Hà! Đó là một mẹo thông minh! Tuy nhiên, nó thực sự sẽ in ====================\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.
terdon

Ngoài ra echo -e '=================\rHello World!!', nhưng có vấn đề tương tự như @terdon chỉ ra rằng.
αғsнιη

1
@ αғsнιη Chỉ khi echohỗ trợ -e. printfhầu như luôn luôn tốt hơn echo, vì nhiều lý do.
Satō Katsura

5

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"

Bạn không cần một vòng lặp : 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.
Satō Katsura

@ SatōKatsura ooh, vâng, thật gọn gàng! Nên nghĩ về điều đó, cảm ơn. Và vâng, tôi đã nghĩ đến việc thêm từ chối trách nhiệm cho sự thất bại có thể xảy ra đối với các ký tự đa byte UTF, nhưng hình dung nó sẽ là một sự phức tạp không cần thiết trong bối cảnh này.
terdon

Tôi nghĩ rằng perl6có 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 perl6gây phiền nhiễu theo nhiều cách.
Satō Katsura

@ SatōKatsura tốt, đối với loại điều đơn giản này, nó là đủ để chỉ cần thiết lập 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").
terdon

5

Một cách khác là chỉ sử dụng printflệ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 $strvà 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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.