การเติมช่องว่างที่ต่อท้ายในสตริงด้วยอักขระอื่น


12

ฉันต้องการส่งออกhello worldมากกว่า 20 ตัวอักษร

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

# Actual output
hello world!!        :

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

อย่างไรก็ตามฉันไม่ต้องการใช้ช่องว่าง แต่ใช้ " = " แทน ฉันจะทำอย่างไร

คำตอบ:


9

คำตอบที่อัปเดตแล้วจะเป็นคำตอบทั่วไป ดูคำตอบอื่นฉันด้านล่างpritnfใช้การขยายตัวรั้งเปลือกเท่านั้นและ

$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:

มันทำงานอย่างไร?

สิ่งนี้(=*):$/จะจับหนึ่งช่องว่างหนึ่งหรือมากกว่า=นั้นตามด้วยเครื่องหมายโคลอน:ในตอนท้ายของอินพุต เราสร้างกลุ่มของ=การจับคู่เป็นกลุ่มและ\1จะอ้างอิงกลับ

ด้วยความ:loopที่เรากำหนดป้ายชื่อloopและt loopมันจะข้ามไปยังป้ายว่าเมื่อs/ (=*):$/\1=:/ได้ทำทดแทนที่ประสบความสำเร็จ

ในส่วนที่แทนที่ด้วย\1=:มันจะเพิ่มจำนวนของ=s และกลับลำไส้ใหญ่ตัวเองไปยังจุดสิ้นสุดของสตริง


1
ดังนั้นคุณต้องปรับค่าสถานะตามจำนวนคำที่ป้อนเข้า
user1686

@grawity ฉันได้อัปเดตคำตอบสำหรับโซลูชันทั่วไปแล้วตอนนี้
αғsнιη

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

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

จะช่วยให้

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

${#string}คือความยาวของค่า$stringและ${filler:${#string}}เป็นสตริงย่อยของ$fillerจาก offset ${#string}เป็นต้นไป

ความกว้างรวมของการส่งออกจะเป็นที่ของความกว้างสูงสุดของหรือ$filler$string

สตริงฟิลเลอร์สามารถสร้างได้บนระบบที่มีjotอยู่แบบไดนามิก

filler=$( jot -s '' -c 16 '=' '=' )

(สำหรับ 16 =ในบรรทัด) ระบบ GNU อาจใช้seq:

filler=$( seq -s '=' 1 16 | tr -dc '=' )

ระบบอื่น ๆ อาจใช้ Perl หรือวิธีอื่นที่เร็วกว่าในการสร้างสตริงแบบไดนามิก


ทำไมไม่ใช้printfเพื่อสร้างตัวกรองที่เกือบจะมีอยู่ในทุกระบบและการขยายรั้งกับเชลล์ชอบbash/szh?
αғsнιη

@sddgob วิธีที่คุณจะทำมันได้ด้วยprintfการขยายตัวรั้ง + ในbash?
Kusalananda

โปรดตรวจสอบunix.stackexchange.com/a/399059/72456
αғsнιη

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

%.20sรูปแบบการตัดสตริงอยู่ที่ไหน


2
นี่คือ IMHO ทางออกที่ดีกว่าของฉัน ต้องการเพียงคำอธิบายสั้น ๆ ของสตริงรูปแบบ
Kusalananda

12

วิธีหนึ่งในการทำ:

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

6
ฮา! นั่นเป็นเคล็ดลับที่ฉลาด! อย่างไรก็ตามมันจะพิมพ์จริง====================\rhello worldซึ่งอาจเป็นปัญหาถ้า OP ต้องการเก็บสิ่งนี้และไม่เพียงพิมพ์ไปที่หน้าจอ
terdon

ยังecho -e '=================\rHello World!!'แต่มีปัญหาเช่นเดียวกับ @terdon ชี้ให้เห็นว่า
αғsнιη

1
@ αғsнιηเฉพาะในกรณีที่ให้การสนับสนุน echo เกือบจะดีกว่าด้วยเหตุผลหลายประการ -eprintfecho
Satō Katsura

5

วิธีการ Perl:

$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======

หรือดีกว่า @SatoKatsura ชี้ให้เห็นในความคิดเห็น:

perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

หากคุณต้องการสนับสนุนอักขระหลายไบต์ UTF ให้ใช้:

PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

แนวคิดเดียวกันในเปลือก:

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"'คุณไม่จำเป็นต้องห่วง: อย่างไรก็ตามวิธีนี้ (และโซลูชันอื่น ๆ ทั้งหมดที่โพสต์จนถึง) จะหยุดพักหากมีอักขระหลายไบต์เข้ามาเกี่ยวข้อง
Satō Katsura

@ SatōKatsuraโอ้โหนั่นเรียบร้อยแล้ว! น่าจะมีความคิดอย่างนั้นขอบคุณ และใช่ฉันคิดที่จะเพิ่มข้อจำกัดความรับผิดชอบสำหรับความล้มเหลวที่อาจเกิดขึ้นกับตัวอักษรหลายไบต์ UTF แต่คิดว่ามันจะเป็นภาวะแทรกซ้อนที่ไม่จำเป็นในบริบทนี้
terdon

ฉันคิดว่าperl6อาจมีวิธีการทำอย่างถูกต้องแม้จะมีตัวละครหลายไบต์ แต่ในทางกลับกันperl6มันน่ารำคาญในหลาย ๆ ด้าน
Satō Katsura

@ PERL_UNICODE='AS'SatōKatsuraดีสำหรับการเรียงลำดับของสิ่งง่ายๆนี้ก็ควรจะพอเพียงชุด ตัวอย่างเช่น: printf '%s' nóóös | perl -nle 'print length($_)'พิมพ์ 8 ("ผิด") ในขณะที่printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'พิมพ์ 5 ("ถูกต้อง")
terdon

5

อีกวิธีหนึ่งคือใช้printfคำสั่งเท่านั้นและสร้างรูปแบบการขยายตัวอักขระแรกโดยShell Brace Expansion(คุณสามารถใส่ท้ายด้วยพื้นที่จัดรูปแบบตัวเลข you ที่คุณต้องการพิมพ์{1..end}) และรับเฉพาะอักขระแรกทุกตัวของมัน%.1sซึ่งเป็น=s แล้วพิมพ์ความยาว 20 อักขระแรกเท่านั้น %.20sพื้นที่ที่ นี่เป็นวิธีที่ดีกว่าในการมีตัวอักษร / คำซ้ำ ๆ

printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:

คำอธิบาย:

โดยปกติแล้วเป็นBrace Expansionให้เชลล์ขยาย{1..20}ดังต่อไปนี้ถ้าเราพิมพ์เหล่านั้น

printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

ดังนั้นเมื่อเพิ่มเครื่องหมายเท่ากับ={1..20}เชลล์จะขยายดังต่อไปนี้

printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20 

และด้วยความprintf '%.1s'ที่เป็นจริงหมายถึงprintf '%WIDE.LENGTH'เรากำลังพิมพ์เพียงหนึ่งความยาวของผู้ที่อยู่ข้างต้นด้วยการเริ่มต้นWIDE1 ดังนั้นจะส่งผล=เฉพาะ s และซ้ำ 20 ครั้งเอง

ขณะนี้printf '%.20s:\n'เรากำลังพิมพ์ความยาวเพียง 20 $strและถ้าความยาว$str<20 ส่วนที่เหลือจะใช้เวลาจาก=s ที่สร้างมาเติมด้วยแทนที่จะเป็นช่องว่าง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.