สะท้อนอักขระแท็บในสคริปต์ทุบตี


313

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

res='       'x # res = "\t\tx"
echo '['$res']' # expect [\t\tx]

ฉันได้รับสิ่งนี้

res=[ x] # that is [<space>x]

คำตอบ:


529
echo -e ' \t '

จะ echo 'ช่องว่างช่องว่างขึ้นบรรทัดใหม่' ( -eหมายถึง 'เปิดใช้งานการตีความเครื่องหมายทับขวา'):

$ echo -e ' \t ' | hexdump -C
00000000  20 09 20 0a                                       | . .|

ขอบคุณโยฮันเนส คุณช่วยฉันหาวิธีแก้ปัญหานี้: res = '\ t \ t'x; echo -e '[' $ res ']'
kalyanji

2
คุณรู้หรือecho -eไม่ว่าทำไมไม่ทำงานจาก Makefiles
dma_k

23
นั่นเป็นเพราะecho -eไม่ใช่ POSIX และการmakeโทร/bin/shซึ่งปกติแล้วไม่ใช่โปรแกรมที่ใช้จะใช้แบบโต้ตอบและโดยปกติจะไม่ได้-eใช้งาน สำหรับการพกพาให้ใช้printf '\t'แทน
Jo So

ในดาร์วิน (MacOS) ที่manหน้าสำหรับคำสั่งไม่ได้พูดถึงตัวเลือกecho -eอย่างไรก็ตามตัวเลือกนี้ได้รับการยอมรับ
ePi272314

75

ใช้ไม่ได้printfecho

echoคำสั่งมีหลายเวอร์ชัน มี/bin/echo(ซึ่งอาจเป็นหรือไม่เป็นรุ่น GNU Coreutils ขึ้นอยู่กับระบบ) และechoคำสั่งนั้นถูกสร้างไว้ในเชลล์ส่วนใหญ่ เวอร์ชันที่ต่างกันมีวิธีที่แตกต่างกัน (หรือไม่มีวิธี) ในการระบุหรือปิดใช้งาน Escape สำหรับอักขระควบคุม

printfในทางกลับกันมีการเปลี่ยนแปลงน้อยกว่ามาก มันสามารถอยู่เป็นคำสั่งโดยทั่วไป/bin/printfและก็สร้างขึ้นในเปลือกหอยบางคน (ทุบตีและ zsh มีมัน tcsh และ ksh ทำไม่ได้) แต่รุ่นต่างๆมีมากขึ้นคล้าย ๆ กันกว่ารุ่นที่แตกต่างกันechoอยู่ และคุณไม่จำเป็นต้องจำตัวเลือกบรรทัดคำสั่ง (มีข้อยกเว้นเล็กน้อย GNU Coreutils printf ยอมรับ--versionและ--helpและ bash printf ในตัวยอมรับ-v varการจัดเก็บเอาต์พุตในตัวแปร)

สำหรับตัวอย่างของคุณ:

res='           'x # res = "\t\tx"
printf '%s\n' "[$res]"

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

echo "[$res]"

ตามที่ kmkaplan เขียน (สองปีครึ่งที่ผ่านมาฉันเพิ่งสังเกตเห็น!) ปัญหาเกี่ยวกับคำสั่งดั้งเดิมของคุณ:

res='           'x # res = "\t\tx"
echo '['$res']' # expect [\t\tx]

ไม่ได้อยู่กับecho; มันคือเปลือกแทนที่แท็บด้วยช่องว่างก่อนที่จะechoเคยเห็นมัน

echoไม่เป็นไรสำหรับเอาต์พุตแบบง่ายเช่นecho hello worldแต่คุณควรใช้printfเมื่อใดก็ตามที่คุณต้องการทำอะไรที่ซับซ้อนกว่านี้ คุณสามารถได้รับechoในการทำงาน แต่รหัสส่งผลให้มีแนวโน้มที่จะล้มเหลวเมื่อคุณเรียกมันด้วยแตกต่างกันechoการดำเนินการหรือเปลือกที่แตกต่างกัน


1
ฉันชอบอันนี้มันช่วยให้ฉันใช้ความรู้ของ printf และตัวระบุรูปแบบทั้งหมด
Arun

@JezenThomas: มันไม่ได้เป็น upvoted มากขึ้นเพราะมันตอบคำถามในทางอื่นมากกว่าที่ร้องขอ คำถามที่กล่าวถึง echo โดยเฉพาะและ echo ไม่ใช่คำกริยา แต่เป็นคำสั่ง
Paulo Neves

@PauloNeves: ฉันจะบอกว่ามันใช้เป็นคำกริยาในคำถาม: "ฉันจะสะท้อนอักขระแท็บอย่างน้อยหนึ่งตัวโดยใช้สคริปต์ทุบตีได้อย่างไร"
Keith Thompson

34

ใส่สตริงของคุณระหว่างเครื่องหมายคำพูดคู่ :

echo "[$res]"

1
เหมือนกันที่นี่ - นี่คือสิ่งที่ฉันพยายามก่อน -e ทำงานได้ดีแม้ว่า
froderik

2
@kmkaplan เหมาะสำหรับฉันใน zsh - ล้มเหลวสำหรับฉันในการทุบตี
Kal

34

คุณสามารถลอง:

echo Hello$'\t'world.

4
+1 สำหรับการแก้ปัญหาทั่วไปเพิ่มเติม ฉันใช้ทุบตีมาหลายปีแล้วและเพิ่งเรียนรู้ตอนนี้!
Aryeh Leib Taurog

นี่เป็นคำทั่วไปที่กว้างกว่าคำตอบที่ยอมรับได้ซึ่งสามารถใช้ได้โดยไม่มีเสียงสะท้อน
jwan


16

จากหน้าคนทุบตี:

คำของฟอร์ม 'string' ได้รับการปฏิบัติเป็นพิเศษ คำขยายออกเป็นสตริงด้วยอักขระเครื่องหมายทับขวาทับกลับแทนที่ตามที่ระบุโดยมาตรฐาน ANSI C

ดังนั้นคุณสามารถทำสิ่งนี้:

echo $'hello\tworld'

เหตุใดจึงทำงานกับ cli แต่ไม่อยู่ในสคริปต์ทุบตี?
Freek

13

ใช้คำต่อคำการกดแป้นพิมพ์^V( CTRL+V, C-v, สิ่งที่ )

เมื่อคุณพิมพ์^Vลงในเทอร์มินัล (หรือในตัวแก้ไข Unix ส่วนใหญ่) อักขระต่อไปนี้จะถูกนำไปใช้คำต่อคำคำต่อคำคุณสามารถใช้สิ่งนี้เพื่อพิมพ์ตัวอักษรแท็บตัวอักษรภายในสตริงที่คุณกำลังสะท้อน

สิ่งที่ชอบทำงานต่อไปนี้:

echo "^V<tab>"     # CTRL+V, TAB

Bash docs ( qv , "quote-insert")

ใบเสนอราคาแทรก (Cq, Cv) เพิ่มอักขระถัดไปที่คุณพิมพ์ลงในบรรทัดคำต่อคำ นี่คือวิธีการแทรกลำดับคีย์เช่น Cq

หมายเหตุด้านข้าง: ตามนี้ ALT+TAB ควรทำสิ่งเดียวกัน แต่เราทุกคนเชื่อมโยงลำดับนั้นกับการสลับหน้าต่างเพื่อให้เราไม่สามารถใช้งานได้

tab-insert (M-TAB) แทรกอักขระแท็บ

-

หมายเหตุ: คุณสามารถใช้กลยุทธ์นี้กับตัวละครที่ผิดปกติทุกประเภท เหมือนการคืนรถ:

echo "^V^M"        # CTRL+V, CTRL+M

นี่เป็นเพราะ carriage return คือ ASCII 13 และMเป็นตัวอักษรที่ 13 ของตัวอักษรดังนั้นเมื่อคุณพิมพ์^Mคุณจะได้รับอักขระ ASCII ที่ 13 คุณสามารถดูได้โดยใช้ls^Mพรอมต์ที่ว่างเปล่าซึ่งจะแทรกการขึ้นบรรทัดใหม่กลับทำให้พรอมต์ทำหน้าที่เหมือนกับที่คุณกดปุ่มย้อนกลับ เมื่อตัวละครเหล่านี้ถูกตีความตามปกติคำต่อคำจะทำให้คุณได้รับตัวอักษรที่แท้จริง


1
หวังว่าฉันจะให้ upvotes มากขึ้นสำหรับคนนี้ ฉันไม่ต้องการใช้ -e ในข้อโต้แย้งของฉันในกรณีนี้และใช้งานได้ดี ขอบคุณ!
Aaron R.

"... บรรณาธิการ Unix ส่วนใหญ่" พยายามป้อนสิ่งนี้ด้วยทั้ง vi และ emacs และไม่ได้ให้ผลลัพธ์ที่ต้องการทั้ง
GreenMatt

มันเจ๋งมาก! และบันทึกวันของฉันเมื่อพยายามใช้grepเพื่อจับเส้นที่มีtabอักขระ
Joël

11

การใช้ echo เพื่อพิมพ์ค่าของตัวแปรเป็นข้อผิดพลาด Bash ทั่วไป ลิงค์อ้างอิง:

http://mywiki.wooledge.org/BashPitfalls#echo_.24foo


เจ๋งฉันชอบ "BashPitfalls" ชิ้นส่วนที่ดีของวัสดุและบรรเทาความเจ็บปวดจากการทำงานประจำวันของฉัน!
Jerry Tian

+1 เพราะนี่เป็นเรื่องจริง แต่โปรดทราบว่าสตริง kalyanji เริ่มต้นด้วย“ [” และไม่มี“ \” ใด ๆ
kmkaplan

2

หากคุณต้องการใช้echo "a\tb"ในสคริปต์คุณเรียกใช้สคริปต์เป็น:

# sh -e myscript.sh

อีกทางเลือกหนึ่งคือคุณสามารถมอบสิทธิ์การใช้งาน myscript.sh ให้กับคุณเพื่อรันสคริปต์

# chmod +x myscript.sh
# ./myscript.sh

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