ฉันจะรับบรรทัดคำสั่งยาวเพื่อตัดบรรทัดถัดไปได้อย่างไร


108

สิ่งที่ฉันสังเกตเห็นใน Ubuntu เป็นเวลานานที่ทำให้ฉันหงุดหงิดคือเมื่อฉันพิมพ์คำสั่งที่บรรทัดคำสั่งที่ยาวขึ้น (กว้างกว่า) มากกว่าความกว้างของเทอร์มินัลแทนที่จะไปที่บรรทัดใหม่มันจะย้อนกลับไปที่ คอลัมน์ 1 ในบรรทัดเดียวกันและเริ่มเขียนทับจุดเริ่มต้นของบรรทัดคำสั่งของฉัน (มันไม่ได้เขียนทับคำสั่งจริง แต่จริงๆแล้วมันเป็นการเขียนทับข้อความที่แสดง)

มันยากที่จะอธิบายโดยไม่เห็นมัน แต่สมมุติว่าเทอร์มินัลของฉันกว้าง 20 ตัวอักษร (ของฉันมีความยาวมากกว่า 120 ตัวอักษร - แต่เพื่อเป็นตัวอย่าง) และฉันต้องการสะท้อนตัวอักษรภาษาอังกฤษ สิ่งที่ฉันพิมพ์คือ:

echo abcdefghijklmnopqrstuvwxyz

แต่หน้าตาเทอร์มินัลของฉันก่อนที่ฉันจะกดปุ่มคือ:

pqrstuvwxyzghijklmno

เมื่อฉันกด Enter มันสะท้อน

abcdefghijklmnopqrstuvwxyz

ดังนั้นฉันรู้ว่าได้รับคำสั่งอย่างถูกต้อง มันเพิ่งพิมพ์ข้อความของฉันหลังจาก "o" และเริ่มต้นใหม่ในบรรทัดเดียวกัน

สิ่งที่ฉันคาดว่าจะเกิดขึ้นถ้าฉันพิมพ์คำสั่งนี้ในเทอร์มินัลที่มีความกว้างเพียง 20 ตัวอักษรจะเป็นดังนี้:

echo abcdefghijklmno
pqrstuvwxyz

พื้นหลัง: ฉันใช้ทุบตีเป็นเปลือกของฉันและฉันมีบรรทัดนี้ใน ~ / .bashrc ของฉัน:

set -o vi

เพื่อให้สามารถนำทางบรรทัดคำสั่งด้วยคำสั่ง VI ฉันกำลังใช้เซิร์ฟเวอร์ Ubuntu 10.10 และกำลังเชื่อมต่อกับเซิร์ฟเวอร์ด้วย Putty

ในสภาพแวดล้อมอื่น ๆ ที่ฉันได้ทำงานถ้าฉันพิมพ์บรรทัดคำสั่งยาวมันจะเพิ่มบรรทัดใหม่ภายใต้บรรทัดที่ฉันกำลังทำงานเมื่อคำสั่งของฉันยาวกว่าความกว้างของเทอร์มินัลและเมื่อฉันพิมพ์ฉันจะเห็นคำสั่งของฉัน 2 สายที่แตกต่างกัน แต่ตราบใดที่ฉันจำอูบุนตูได้คำสั่งยาว ๆ ของฉันใช้แค่ 1 บรรทัดเท่านั้น

สิ่งนี้ยังเกิดขึ้นเมื่อฉันกลับไปที่คำสั่งก่อนหน้าในประวัติศาสตร์ (ฉันกด Esc แล้ว 'K' เพื่อกลับไปยังคำสั่งก่อนหน้า) - เมื่อฉันไปที่คำสั่งก่อนหน้าซึ่งยาวกว่าความกว้างเทอร์มินัลบรรทัดคำสั่งจะได้รับ mangled และฉันไม่สามารถบอกได้ว่าฉันอยู่ที่ไหนในคำสั่ง

สิ่งเดียวที่ฉันได้พบเมื่อเห็นคำสั่งยาวทั้งหมดคือกด "Esc-V" ซึ่งเปิดคำสั่งปัจจุบันในเครื่องมือแก้ไข VI

ฉันไม่คิดว่าฉันมีอะไรแปลกในไฟล์. bashrc ของฉัน ฉันแสดงความคิดเห็นในบรรทัด "set -o vi" และฉันยังคงมีปัญหา

ฉันดาวน์โหลดสำเนาใหม่ของ Putty และไม่ได้ทำการเปลี่ยนแปลงใด ๆ กับการกำหนดค่า - ฉันเพิ่งพิมพ์ชื่อโฮสต์เพื่อเชื่อมต่อและฉันยังคงมีปัญหาดังนั้นฉันจึงไม่คิดว่ามันจะเป็นเรื่องของ Putty (เว้นแต่ฉันต้องการ ทำการเปลี่ยนแปลงการกำหนดค่าบางอย่าง)

มีใครมีปัญหานี้และใครจะคิดวิธีการแก้ไขได้หรือไม่

แก้ไข

มันเป็นไฟล์. bashrc ของฉัน ฉันได้คัดลอกโปรไฟล์เดียวกันจากเครื่องไปยังเครื่องและฉันใช้ตัวละครพิเศษใน $ PS1 ของฉันที่ทิ้งมันไป ตอนนี้ฉันติดกับตัวแปร bash มาตรฐานสำหรับ $ PS1 ของฉัน

ขอบคุณ @ ændrükสำหรับเคล็ดลับใน. bashrc!

... สิ้นสุดการแก้ไข ...


1
เพียงเพื่อให้แน่ใจว่าปัญหาไม่ได้เกิดจากไฟล์. bashrc ของคุณฉันขอแนะนำให้แทนที่ด้วยสำเนา/etc/skel/.bashrcชั่วคราว โปรดทราบว่าคุณจะต้องเชื่อมต่อใหม่เพื่อให้การเปลี่ยนแปลงมีผลและให้แน่ใจว่าได้สำรองข้อมูลของ. bashrc ของคุณเอง
ændrük

1
คุณใช้แอปพลิเคชั่นเทอร์มินัลใด พฤติกรรมที่คุณอธิบายไม่ปกติไม่ใช่ค่าเริ่มต้น
João Pinto

ในเชลล์ที่ฉันได้ทำงาน (และใน Cisco CLI) คุณยังสามารถพิมพ์ Ctrl-L เพื่อแสดงบรรทัดที่คุณพิมพ์อีกครั้งแม้ว่าจะอยู่นอกจอ ในสถานการณ์ของคุณที่อาจยังให้ผลผลิตที่ขาดซึ่งคุณกำลังพูดถึง แต่ฉันอยากรู้
belacqua

3
อย่าลังเลที่จะสร้าง "คำตอบ" เพื่ออธิบายวิธีแก้ปัญหาและทำเครื่องหมายว่าได้รับการยอมรับ มันอาจดูโง่ไปหน่อย แต่การมีคำตอบที่เหมาะสมช่วยให้ไซต์จัดระเบียบและอาจแนะนำผู้อื่นที่มีปัญหาคล้ายกันในอนาคตได้อย่างมีประสิทธิภาพยิ่งขึ้น
ændrük

ตามคำตอบนี้ใน serverfaultให้ใช้tput smam
Samveen

คำตอบ:


136

ให้แน่ใจว่าทั้งหมดไบต์ไม่พิมพ์ใน PS1 \[ \]ของคุณจะถูกบรรจุอยู่ภายใน มิฉะนั้นการทุบตีจะนับจำนวนตามความยาวของพรอมต์ มันใช้ความยาวของพรอมต์เพื่อกำหนดเวลาที่จะตัดเส้น

ตัวอย่างเช่นที่นี่ทุบตีนับพรอมต์ให้มีความกว้าง 19 คอลัมน์ในขณะที่พรอมต์ที่แสดงโดยเทอร์มินัลมีความกว้างเพียง 10 คอลัมน์ ( My promptเขียนเป็นสีฟ้าและ>เขียนด้วยสีเริ่มต้น):

PS1='\e[36mMy prompt\e[0m>'         # bash count: 19, actual: 10

ในขณะที่ที่นี่จะนับเฉพาะพรอมต์ที่มีความกว้าง 10 คอลัมน์เนื่องจากจะละเว้นไบต์ระหว่างการพิเศษ\[และการ\]หลบหนี:

PS1='\[\e[36m\]My prompt\[\e[0m\]>' # bash count: 10, actual: 10

เพื่อการปฏิบัติที่ดีควรใช้tputเพื่อสร้างเทอร์มินัลหลบหนีมากกว่าการเข้ารหัสอย่างหนัก:

cyan=$(tput setaf 6) # \e[36m
reset=$(tput sgr0)   # \e[0m
PS1='\[$cyan\]My prompt\[$reset\]>'

ดูhttp://mywiki.wooledge.org/BashFAQ/053และยังhttp://wiki.bash-hackers.org/scripting/terminalcodestputสำหรับข้อมูลเพิ่มเติมเกี่ยวกับ


3
นั่นเป็นคำอธิบายที่ดีของปัญหาที่คำตอบที่ยอมรับไม่ได้
เจมี่คุก

ในบรรทัดสุดท้ายของรหัสPS1='...': เหตุใดเครื่องหมายคำพูดเดี่ยวจึงป้องกัน$cyanและ$resetทดแทน
andrybak

2
@ andrybak พวกเขาป้องกัน$cyanและ$resetจากการถูกแทนที่ แต่PS1จะมีการประเมินทุกครั้งที่พิมพ์พรอมต์ คุณสามารถดูสิ่งนี้ได้โดยลองPS1='$var> 'แล้วให้varค่าต่าง ๆ และดูว่าการเปลี่ยนแปลงที่พรอมต์ จากนั้นลองPS1="$var> " สังเกตว่าพรอมต์นั้นคงที่ $varถูกขยายระหว่างการมอบหมายไม่ใช่ทุกครั้งที่PS1ถูกประเมิน
geirha

1
มันอัศจรรย์มาก. ขอบคุณมากที่โพสต์ข้อความนี้! มันทำให้การหลบหลีกวงเล็บเหลี่ยมง่ายขึ้นและอ่านง่ายขึ้น
phyatt

ฉันทำงานนี้PS1=${PS1}"\e]2;$@\a"ได้อย่างไร ฉันลองแล้วPS1=${PS1}"\[\e]2;\]$@\[\a\]"
Ramana Reddy

59

ฉันเดาว่าคุณได้ตั้งค่าPS1สีด้วยใช่มั้ย

เพียงให้แน่ใจว่าคุณมี\[อยู่ในPS1คำพูดของคุณก่อนหน้าชุดสีของคุณ

ตัวอย่างเช่น:

PS1='\[\e[0;32m\u@\w/:\[\e[m '

PS1 ของฉันคือexport PS1='^[[96m'$(hostname)'<^[[92m${PWD}^[[96m>^[[97m '- ฉันใช้อันนั้นมานาน - มันเข้ากันได้กับ KSH ...
BrianH

2
ว้าว. ฉันใช้เทอร์มินัลพรอมต์ตลอดไปและไม่เคยมีปัญหานี้มาก่อน คงไม่เคยคิดออกว่า ขอบคุณ
bchurchill

3
การใช้ \ [ในขณะที่ใช้เครื่องหมายคำพูดง่าย ๆ จะทำให้เกิดเครื่องหมายทับที่ไม่ตั้งใจ นอกจากนี้ควรใช้] ในตอนท้ายของตัวอักษรวิเศษดังที่ระบุไว้ในคำตอบที่ได้รับการโหวตดีที่สุด
igorsantos07

2
-1 ใช้งานไม่ได้ คุณต้องตัดส่วนที่ไม่พิมพ์ออกมาด้วย\[ตอนเริ่มต้นและ\]ตอนท้าย
wjandrea

@ igorsantos07 double-backslash in \\[เป็นตัวพิมพ์ที่เกิดจากการแก้ไข ฉันแก้ไขมันแล้ว
wjandrea

11

ฉันมีปัญหาที่คล้ายกันและในที่สุดก็พบทางออกที่ง่าย

เพิ่มบรรทัดต่อไปนี้ใน.bashrcไฟล์ของคุณ:

COLUMNS=250

จากนั้นพิมพ์source ~/.bashrcเพื่อให้ได้เอฟเฟกต์ที่ต้องการ


ในบางกรณีเช่นเขตการย่อยเทอร์มิเนเตอร์แคบปัญหาไม่ได้อยู่ในตัวอักษรสี promt แต่เป็นเพียงค่า COLUMNS ที่ไม่ถูกต้อง คำตอบนี้พาฉันออกจากหลุมที่น่ารำคาญมาก!
Carles Sala

1
การออกจากระบบไม่จำเป็น source .bashrcทำ ข้อความแจ้งของคุณจะอัปเดตทันที
Sergiy Kolodyazhnyy

1
ฉันพบว่าเนื่องจากฉันไม่ได้setwinsizeตั้งค่าshopt ไว้สำหรับทุบตีของฉันดังนั้นจึงไม่อัปเดต COLUMNS ถูกต้องโปรดดูunix.stackexchange.com/a/167911/8337
rogerdpack

1
ฉันexport COLUMNS=250ตามมาด้วยexport TERM=xtermและมันก็มีความสุข
Philip Kearns

5

ฉันมีปัญหาเดียวกันกับพรอมต์สีที่กำหนดเองแม้ว่าฉันจะมีรหัสสีภายใน\[และ\]ตัวคั่น แต่กลับกลายเป็นว่าทุบตีมีปัญหาในการสะท้อนสีจากภายในฟังก์ชั่น ฉันลงเอยด้วยการใช้ตัวแปรสำหรับพรอมต์ของฉันและแม้ว่า. bashrc ของฉันจะดูสง่างามน้อยลง แต่ตอนนี้ทุกอย่างทำงานได้ดี


หากใครยังคงอ่านข้อความนี้มันเป็นไปได้จริงที่จะหลบหนีสีในฟังก์ชัน ดูคำตอบนี้ในคำถามที่เชื่อมโยง
wjandrea

3

สิ่งที่ต้องทำง่ายๆคือการเพิ่มบรรทัดต่อไปนี้ก่อนที่จะตั้งค่า PS1:

stty columns 1000

ตัวอย่างเช่น,

stty columns 1000
PS1='\[\e[0;32m\u@\w/:[\e[m '

อย่างไรก็ตามสิ่งนี้จะมีผลกับคำสั่ง unix อื่น ๆ เช่น ls และ man


1
ใช้งานได้ใน OSX
raskhadafi

4
สิ่งนี้มีผลต่อความรู้สึกไม่ดีเช่นกัน โปรดอย่าใช้สิ่งนี้
justhalf

0

ฉันมีปัญหานี้เมื่อเชื่อมต่อใน tmux ปัญหาคือว่าฉันมีipythonเซสชั่นในพื้นหลัง ( ctrl + z) และที่ทำลายเส้นอย่างใด ทันทีที่ผมบอกเลิกมัน ( fg, ctrl+d+d) ขั้วของฉันเริ่มต้นทำงานอย่างถูกต้อง

ดังนั้นตรวจสอบการแจ้งเตือนแบบโต้ตอบที่หยุด


0

ดังนั้นผมก็มีปัญหาเดียวกันกับเล็กน้อยบิดบนมันและฉันคิดว่าฉันจะแบ่งปันวิธีการแก้ปัญหาของฉันเกินไปเพียงเพื่อเพิ่มความแตกต่างเล็ก ๆ น้อย ๆ ของฉัน: D

PS1 เริ่มต้นของฉันคือ

PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$"

ปัญหาที่ฉันมีคือฉันพยายามเปลี่ยนชื่อเทอร์มินัลรวมถึงพรอมต์คำสั่ง วิธีที่ผมทำนี้คือโดยการเพิ่ม\[\033]0;\]Title\aไปPS1ตัวแปร

ดังนั้นตอนนี้ PS1 ของฉันคือ:

PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$\[\033]0;\]Title\a"

สิ่งนี้ทำให้ผมยุ่งเหยิง ในที่สุดฉันก็พบว่าการทุบตีนั้นดูเหมือนจะไม่\aสิ้นสุด เพื่อหลีกเลี่ยงสิ่งนี้ฉันใส่หัวเรื่องในตัวแปรซึ่งดูเหมือนจะแก้ไขได้

TITLE="\033]0;Title\a"
PS1="\[\033[01;32m\]\u\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$\[$TITLE\]"

0

\[และ\]ไม่ทำงานสำหรับฉัน ฉันเดาว่ามีบางสิ่งที่แตกต่างกันเกี่ยวกับวิธีสร้างพรอมต์ (จากโปรแกรมภายนอก) หรือเพราะพรอมต์ของฉันคือ "ไดนามิก"

หลังจากอ่านสิ่งนี้ฉันพบว่าคุณสามารถหลบหนีรหัสสีด้วย0x01และ0x02ไบต์

เช่นฉันใช้Chalkรุ่นพิเศษและฉันใช้สีนี้:

const Chalk = require('@nasc/chalk');

const chalk = new Chalk.constructor({
  wrapper: {
    pre: '\1',
    post: '\2',
  }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.