วิธีการพิมพ์สตริงคั่นด้วย TAB ในทุบตี?


9

ฉันพยายามพิมพ์สองสตริงคั่นด้วย TAB ฉันเหนื่อย:

echo -e 'foo\tbar'
printf '%s\t%s\n' foo bar

ทั้งคู่พิมพ์:

foo     bar

โดยที่ช่องว่างระหว่างสองช่องนั้นเป็น 5 ช่องว่าง (ตามการเลือกผลลัพธ์ด้วยเมาส์ใน Putty)

ฉันได้ลองใช้ CTRL + V แล้วกด TAB เมื่อพิมพ์คำสั่งด้วยผลลัพธ์เดียวกัน

วิธีที่ถูกต้องในการบังคับแท็บให้พิมพ์เป็นแท็บคืออะไรฉันจึงสามารถเลือกเอาท์พุทและคัดลอกไปยังที่อื่นด้วยแท็บได้

และคำถามรอง: ทำไมทุบตีขยายแท็บลงในช่องว่าง

อัปเดต : เห็นได้ชัดว่านี่เป็นปัญหาของ Putty: /superuser/656838/how-to-make-putty-display-tabs-within-a-file-instead-of-changing-them-to ช่องว่างที่



ทำไมไม่หนีไปล่ะ? printf '%s\\t%s\n' foo bar
Valentin Bajrami

@steeldriver ขอบคุณที่คล้ายกันมากกับสิ่งที่ฉันต้องการ แต่ในท้ายที่สุดไม่มีวิธีการแก้ปัญหา ...
เอส

1
@Valentin ผลลัพธ์นั้นfoo\tbar...
wjandrea

1
แม้ว่าข้อเท็จจริงที่ว่าคุณรู้อยู่แล้วว่าคุณมีปัญหากับเทอร์มินัลของคุณ: ทุบตีโดยตีความ$'\t'เป็น tabulator ดังนั้นคุณสามารถเชื่อมโยงสตริงเช่นนี้ได้ตลอดเวลา - ตัวอย่างเช่นการมอบหมาย: v='This is'$'\t''a test'และการพิมพ์อย่างแท้จริงเช่นprintf '%s' "$v"
rexkogitans

คำตอบ:


9

เช่นเดียวกับ ilkkachu กล่าวว่านี่ไม่ใช่ปัญหาของ bash แต่ด้วยเทอร์มินัลอีมูเลเตอร์ซึ่งแปลงแท็บเป็นช่องว่างในเอาต์พุต

การตรวจสอบเทอร์มินัล, putty, xterm และ konsole ที่แตกต่างกันจะแปลงแท็บเป็นช่องว่างในขณะที่ urxvt และ gnome-terminal ไม่ทำเช่นนั้น อีกวิธีหนึ่งคือการสลับขั้ว


3
นอกจากนี้ยังสามารถทำได้โดยการขับรถ TTY stty tab3หลังจากที่คุณเรียก
Stéphane Chazelas

14

ช่องว่างระหว่างทั้งสองเป็นจริง 5 ช่องว่าง

ไม่มันไม่ใช่. ไม่ได้อยู่ในการส่งออกของหรือechoprintf

$ echo -e 'foo\tbar' | od -c
0000000   f   o   o  \t   b   a   r  \n
0000010

วิธีที่ถูกต้องในการบังคับแท็บให้พิมพ์เป็นแท็บคืออะไรฉันจึงสามารถเลือกเอาท์พุทและคัดลอกไปยังที่อื่นด้วยแท็บได้

นี่เป็นปัญหาที่แตกต่าง มันไม่ได้เกี่ยวกับเชลล์ แต่เป็นเทอร์มินัลอีมูเลเตอร์ซึ่งแปลงแท็บเป็นช่องว่างในเอาต์พุต หลายคน แต่ไม่ใช่ทั้งหมดทำเช่นนั้น

การเปลี่ยนเส้นทางเอาต์พุตด้วยแท็บไปยังไฟล์อาจทำได้ง่ายกว่าและคัดลอกจากที่นั่นหรือใช้unexpandกับเอาต์พุตเพื่อแปลงช่องว่างเป็นแท็บ (แม้ว่ามันจะไม่สามารถรู้ได้ว่าช่องว่างคือแท็บเริ่มต้นและจะแปลงแท็บทั้งหมดให้เป็นแท็บถ้าเป็นไปได้) แน่นอนว่าสิ่งนี้ขึ้นอยู่กับว่าคุณต้องการทำอะไรกับผลลัพธ์


ฉันหมายถึงว่าเมื่อฉันพยายามเลือกเอาต์พุตมันจะถูกรักษาเป็น 5 ช่องว่าง ขอบคุณสำหรับ 'od -c' เพื่อตรวจสอบเนื้อหาของเอาต์พุตคำสั่ง
Asu

1
@ ฉันคิดว่าเขาเข้าใจดี วิธีแก้ปัญหาของเขาคือรับเอาท์พุทด้วยวิธีอื่นเนื่องจากเทอร์มินัลอีมูเลเตอร์ไม่รับประกันว่าจะปล่อยแท็บไว้เป็นแท็บเมื่อคุณเลือกในหน้าต่าง อย่างไรก็ตามฉันเพิ่งตรวจสอบและในขณะที่ putty, xterm และ konsole แปลงแท็บเป็นช่องว่าง urxvt และ gnome-terminal ไม่ทำ อีกวิธีหนึ่งคือการสลับขั้ว
JoL

@JoL ใช่นั่นคือข้อสรุปที่ฉันเพิ่งมาเมื่อไม่กี่นาทีที่ผ่านมาและฉันคิดว่ามันจะเป็นคำตอบที่ได้รับการยอมรับถ้าใครบางคนสนใจที่จะโพสต์มันเช่นนี้ ...
Asu

1
@Asu ใช่ฉันคิดเพียงแค่แก้ไขปัญหาด้วยตนเอง มันน่ารำคาญที่ต้องทำอย่างนั้น แต่แล้วฉันก็ยอมรับว่าฉันไม่ได้ตระหนักว่ามีเทอร์มินัลอีมูเลเตอร์ที่รองรับการคัดลอกแท็บ แน่นอนว่าการเปลี่ยนเป็นสิ่งที่ดีจะเป็นทางออกที่ดีกว่ามาก!
ilkkachu

4

ในprintf '%s\t%s\n' foo bar, ไม่เอาท์พุทprintffoo<TAB>bar<LF>

f, o, b, aและrมีตัวอักษรกราฟิกเดียวกว้าง

เมื่อรับตัวอักษรเหล่านั้นเทอร์มินัลจะแสดงสัญลักษณ์และเลื่อนเคอร์เซอร์ไปหนึ่งคอลัมน์ทางด้านขวายกเว้นว่าได้มาถึงขอบด้านขวาของหน้าจอแล้ว (กระดาษในเครื่องพิมพ์ดีดดั้งเดิม) ซึ่งในกรณีนี้อาจป้อนบรรทัด และกลับไปที่ขอบด้านซ้ายของหน้าจอ (ตัด) หรือเพียงแค่ทิ้งอักขระขึ้นอยู่กับเทอร์มินัลและวิธีการกำหนดค่า

<Tab>และ<LF>เป็นอักขระควบคุมสองตัว <LF>(aka newline) เป็นตัวคั่นบรรทัดในข้อความ Unix แต่สำหรับเทอร์มินัลเพียงป้อนบรรทัด (เลื่อนเคอร์เซอร์หนึ่งตำแหน่งลง) ดังนั้นไดรเวอร์เทอร์มินัลในเคอร์เนลจะแปลเป็นจริง<CR>(กลับไปที่ขอบด้านซ้ายของหน้าจอ) <LF>(เลื่อนเคอร์เซอร์ลง) ( stty onlcrโดยทั่วไปจะเป็นค่าเริ่มต้น)

<Tab> บอกให้เทอร์มินัลเลื่อนเคอร์เซอร์ไปที่แท็บหยุดถัดไป (ซึ่งในเทอร์มินัลส่วนใหญ่จะอยู่ห่างกัน 8 ตำแหน่งโดยค่าเริ่มต้น แต่ยังสามารถกำหนดค่าให้ตั้งค่าได้ทุกที่) โดยไม่ต้องเติมช่องว่างด้วยช่องว่าง

ดังนั้นหากอักขระเหล่านั้นถูกส่งไปยังเทอร์มินัลพร้อมแท็บหยุดทุก 8 คอลัมน์ในขณะที่เคอร์เซอร์อยู่ที่จุดเริ่มต้นของบรรทัดว่างนั่นจะส่งผลให้:

foo     bar

พิมพ์บนหน้าจอที่บรรทัดนั้น หากพวกเขาถูกส่งในขณะที่เคอร์เซอร์อยู่ในตำแหน่งที่สามในบรรทัดที่มีxxxxyyyyzzzzที่จะส่งผลใน:

xxfooyyybarz

ในเทอร์มินัลที่ไม่สนับสนุนการจัดระเบียบคุณสามารถกำหนดค่าไดรเวอร์เทอร์มินัลให้แปลแท็บเหล่านั้นเป็นลำดับของช่องว่างได้ ( stty tab3)

อักขระ SPC ในเครื่องพิมพ์ดีดดั้งเดิมจะย้ายเคอร์เซอร์ไปทางขวาขณะที่ backspace ( \b) จะย้ายไปทางซ้าย ตอนนี้ในอาคารทันสมัย ​​SPC ย้ายไปทางขวาและลบ (เขียนอักขระเว้นวรรคตามที่คุณคาดหวัง) ดังนั้นการจี้ของ\bต้องเป็นสิ่งที่ใหม่กว่า ASCII บนขั้วที่ทันสมัยที่สุดก็จริงลำดับตัวอักษร: <Esc>, ,[C

มีลำดับการหลีกเลี่ยงเพิ่มเติมเพื่อเลื่อนnอักขระไปทางซ้ายขวาขึ้นลงหรือตำแหน่งใด ๆ บนหน้าจอ มีลำดับการหลีกเลี่ยงอื่น ๆ ที่จะลบ (เติมด้วยช่องว่าง) ส่วนของบรรทัดหรือภูมิภาคของหน้าจอ ฯลฯ

ลำดับผู้ที่มักจะใช้โดยการใช้งานภาพเหมือนvi, lynx, mutt, dialogที่เขียนข้อความที่ตำแหน่งพลบนหน้าจอ

ในตอนนี้เทอร์มินัลอีมูเลเตอร์ X11 และอุปกรณ์อื่นที่ไม่ใช่ X11 อย่าง GNU screenช่วยให้คุณสามารถเลือกพื้นที่ของหน้าจอเพื่อคัดลอก เมื่อคุณเลือกส่วนหนึ่งของสิ่งที่คุณเห็นในตัวviแก้ไขคุณไม่ต้องการคัดลอกลำดับ escape ทั้งหมดที่ใช้ในการสร้างเอาต์พุตนั้น คุณต้องการเลือกข้อความที่คุณเห็นที่นั่น

เช่นถ้าคุณเรียกใช้:

printf 'abC\rAC\bB\t\e[C\b\bD\n'

ซึ่งจำลองเซสชั่นการแก้ไขที่คุณป้อนabCกลับไปยังจุดเริ่มต้นให้แทนที่abด้วยAC, Cมีย้ายไปที่ป้ายแท็บถัดไปแล้วหนึ่งคอลัมน์มากขึ้นไปทางขวาแล้วสองคอลัมน์ไปทางซ้ายแล้วป้อนBD

คุณเห็น:

ABC    D

นั่นคือABCช่องว่าง 4 Dคอลัมน์

หากคุณเลือกที่ด้วยเมาส์ในxtermหรือputtyพวกเขาจะจัดเก็บในส่วนที่เลือกABC4 ตัวอักษรพื้นที่และไม่DabC<CR>AC<BS>B<Tab><Esc>[C<BS><BS>D

สิ่งที่เกิดขึ้นในการเลือกคือสิ่งที่ถูกส่งโดยprintfแต่ผ่านการประมวลผลทั้งไดรเวอร์เทอร์มินัลและเทอร์มินัลอีมูเลเตอร์

สำหรับชนิดอื่น ๆ ของการเปลี่ยนแปลงให้ดู<U+0065><U+0301>( eตามสำเนียงเฉียบพลันรวม) เปลี่ยนไป<U+00E9>( éแบบฟอร์มก่อนแต่ง) xtermโดย

หรือecho abcว่าปลายถูกแปลไปโดยคนขับรถมินัลก่อนที่จะส่งไปยังสถานีหลังจากที่ABCstty olcuc

ตอนนี้<Tab>Like <LF>เป็นหนึ่งในอักขระควบคุมบางตัวที่บางครั้งพบได้ในไฟล์ข้อความ (เช่น<CR>ในไฟล์ข้อความ MSDOS และบางครั้ง<FF>เป็นตัวแบ่งหน้า)

ดังนั้นเทอร์มินัลอีมูเลเตอร์บางคนเลือกที่จะคัดลอกเมื่อเป็นไปได้ในบัฟเฟอร์การคัดลอกเพื่อเก็บไว้ (โดยทั่วไปไม่ใช่กรณี<CR>หรือ<LF>แม้ว่า)

ยกตัวอย่างเช่นในอาคารเช่น VTE-based gnome-terminal, คุณอาจจะเห็นว่าเมื่อคุณเลือกการส่งออกของprintf 'a\tb\n'ในบรรทัดที่ว่างเปล่าgnome-terminalร้านค้าจริงa\tbในการเลือกแทน X11 a, 7 bช่องว่างและ

แต่สำหรับการส่งออกของprintf 'a\t\bb\n'ร้านค้ามันa, 6 ช่องว่างและbและสำหรับprintf 'a\r\tb\n', a7 bช่องว่างและ

มีอีกหลายกรณีที่เทอร์มินัลจะพยายามคัดลอกอินพุตจริงเช่นเมื่อคุณเลือกสองบรรทัดหลังจากทำงานในprintf 'a \nb\n'ที่ที่ส่วนท้ายที่มองไม่เห็นจะถูกเก็บรักษาไว้ หรือเมื่อเลือกสองบรรทัดจะไม่มีอักขระ LF เมื่อทั้งสองบรรทัดเกิดจากการตัดที่ขอบขวา

ตอนนี้ถ้าคุณต้องการเก็บเอาท์พุทของprintfลงในการX11เลือกคลิปบอร์ดที่ดีที่สุดคือการทำมันโดยตรงเช่น:

printf 'foo\tbar\n' | xclip -sel c

โปรดทราบว่าเมื่อคุณวางลงในxtermเทอร์มินัลหรืออื่น ๆ ส่วนใหญ่xtermแล้วแทนที่\nด้วย\rเพราะเป็นตัวละครที่xtermส่งเมื่อคุณกดEnter(และไดรเวอร์เทอร์มินัลอาจแปลมันกลับไป\n)


ขอบคุณมาก ฉันลองโซลูชัน xclip แล้วและใช้งานได้ แต่มันไม่ได้ทำสิ่งที่ฉันคิดอยู่ในใจและต้องการ X11 อาจเป็นเช่นนี้จะมีประโยชน์ในบางจุดขอบคุณ!
Asu

@Asu X11เป็นสิ่งที่จัดการการคัดลอกวางในเทอร์มินัลอีมูเลเตอร์เช่นxtermหรือputtyบน Unix เทอร์มินัลอีมูเลเตอร์อื่นอาจมีกลไกการคัดลอกและวิธีการจัดเก็บเนื้อหาโดยพลการในนั้นเช่นreadbuf และregisterคำสั่งในหน้าจอ GNU
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.