วิธีอ่านอินพุตมากกว่า 4k โดยไม่มีบรรทัดใหม่บนเทอร์มินัล


25

ดังนั้นฉันจึงมีข้อมูลจำนวนมากโดยไม่ต้องมีบรรทัดใหม่บนคลิปบอร์ด (เป็นไฟล์ SVG ขนาดใหญ่ในหนึ่งบรรทัด) ฉันไป

$ cat >file.svg

จากนั้นพยายามวาง (ในเทอร์มินัล Gnome) แต่ยอมรับเฉพาะอักขระขนาด 4kB แรกเท่านั้น

ฉันถือว่านี่เป็นคุณสมบัติ / ข้อ จำกัด readline

มีวิธีอ่านจาก STDIN ที่จะหลีกเลี่ยงปัญหานี้หรือไม่?

แก้ไข

กรณีทดสอบ: สร้างไฟล์ตัวอย่าง อันนี้จะมีสัญลักษณ์ ~ 4k "=" ตามด้วย "foo bar"

{ printf '=%.0s' {1..4095} ; echo "foo bar" ; } > test.in

คัดลอกลงในคลิปบอร์ดของคุณ

xclip test.in

(หากคุณต้องการคลิกกลางที่จะแทรก) หรือ

xclip -selection clipboard test.in

(ถ้าคุณต้องการใช้ Ctrl-Shift-Insert เพื่อผ่านเข้าไป)

จากนั้นcat >test.outวาง (วิธีใดก็ได้) กด Ctrl-D เพื่อสิ้นสุดสตรีม cat test.out- คุณเห็น "foo bar" หรือไม่

เกี่ยวกับการตั้งค่าของฉัน (Ubuntu 12.04, Gnome สถานี zsh) เมื่อฉันวางฉันเท่านั้นที่เห็นและผมก็ไม่เห็น= เดียวกันเมื่อผมตรวจสอบfoo bartest.out


คุณแน่ใจหรือไม่ว่าไฟล์ SVG ของคุณถูกอ่านทั้งหมดในคลิปบอร์ดของคุณ?
lgeorget

ปัญหาที่แท้จริงของคุณคืออะไร จะเก็บเนื้อหาของคลิปบอร์ดไปยังไฟล์ได้อย่างไร? ถ้าเป็นเช่นนั้นมีวิธีอื่นนอกเหนือจากการวางในเครื่อง
lgeorget

คุณมี N เท่าไหร่ในกรณีของคุณ? ฉันได้ลองกับ xml data (inc LF) 2kB แล้วไม่มีปัญหา
fduff

1
@artfulrobot กระบวนการทำงานเบื้องหน้าโต้ตอบกับ tty / pty โดยตรง เปลือกไม่เกี่ยวข้อง คุณสามารถเห็นสิ่งนี้ได้เนื่องจากคุณไม่มีคุณสมบัติ readline (คำสั่งแก้ไข / กระโดด, ประวัติ, ... ) ในโปรแกรมหากพวกเขาไม่ได้ใช้ readline หรือไลบรารีอินพุตอื่น ๆ
jofel

1
นี่ไม่ใช่ข้อ จำกัด ของ readline - readline และ bash ไม่มีส่วนเกี่ยวข้องที่นี่ เป็นข้อ จำกัด ของส่วนต่อประสานเทอร์มินัล
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

คำตอบ:


22

หากฉันเข้าใจแหล่งที่มาอย่างถูกต้องภายใต้ Linux จำนวนอักขระสูงสุดที่สามารถอ่านได้ในหนึ่งครั้งบนเทอร์มินัลจะถูกกำหนดโดยN_TTY_BUF_SIZEในแหล่งเคอร์เนล ค่าเป็น 4096

นี่เป็นข้อ จำกัด ของส่วนต่อประสานเทอร์มินัลโดยเฉพาะโหมดcanonical (“ สุก”)ซึ่งมีตัวแก้ไขบรรทัดที่หยาบมาก (backspace ป้อนCtrl+ + Dที่จุดเริ่มต้นของบรรทัดสำหรับสิ้นสุดไฟล์) มันเกิดขึ้นนอกกระบวนการที่กำลังอ่านอยู่ทั้งหมด

คุณสามารถสลับเทอร์มินัลเป็นโหมด raw ซึ่งปิดใช้งานการประมวลผลบรรทัด นอกจากนี้ยังปิดใช้งานCtrl+ Dและเครือข่ายอื่น ๆ ทำให้มีภาระเพิ่มเติมในโปรแกรมของคุณ

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

ตัวอย่างเช่นการใช้เนื้อหาของคลิปบอร์ด X ที่ท่อจากหรือxsel xclipในกรณีของคุณ:

xsel -b >file.svg
xclip -selection clipboard >file.svg

ลบ-bหรือ-selection clipboardใช้การเลือก X (รายการที่กำหนดโดยเน้นด้วยเมาส์) แทนคลิปบอร์ด

บน OSX ใช้pbpasteเพื่อวางเนื้อหาของคลิปบอร์ด (และpbcopyเพื่อตั้งค่า)

คุณสามารถเข้าถึงคลิปบอร์ด X บน SSH หากคุณเปิดใช้งานการส่งต่อ X11 ด้วยssh -X(ซึ่งเซิร์ฟเวอร์บางตัวอาจห้าม) หากคุณสามารถใช้sshโดยไม่ต้องส่ง X11 คุณสามารถใช้scp, sftpหรือsshfsคัดลอกไฟล์

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

xsel -b | base64 | xsel -b

จากนั้นถอดรหัส:

base64 -d
 Paste
Ctrl+D

โปรดทราบว่ามีข้อผิดพลาดข้อมูลเสียหายที่น่ารังเกียจจริงๆเมื่อใช้xselกับ> 4k ไบต์: github.com/kfish/xsel/issues/14
Patrick

14

ขีด จำกัด ที่คุณกำลังทำงานเป็นเป็นขนาดสูงสุดของสายในโหมดการป้อนข้อมูลที่ยอมรับMAX_CANON ,

ในโหมดอินพุตแบบ canonical ไดรเวอร์ tty จัดเตรียมบริการแก้ไขบรรทัดพื้นฐานดังนั้นโปรแกรม userspace ไม่จำเป็นต้องใช้ มันมีคุณสมบัติไม่มากพอ ๆ กับ readline แต่มันจำตัวอักษรพิเศษที่กำหนดค่าได้ไม่กี่ตัวเช่นการลบ (โดยปกติคือ Backspace หรือ Delete) และ kill (โดยทั่วไปคือ Ctrl-U)

ที่สำคัญที่สุดสำหรับคำถามของคุณบัฟเฟอร์โหมด canonical อินพุตจนกว่าจะเห็นอักขระสิ้นสุดบรรทัด เนื่องจากบัฟเฟอร์อยู่ในไดรเวอร์ tty ในหน่วยความจำเคอร์เนลจึงไม่ใหญ่มาก

คุณสามารถปิดโหมด canonical ด้วยstty cbreakหรือstty -icanonจากนั้นทำการวาง นี่เป็นข้อเสียที่สำคัญที่คุณจะไม่สามารถส่ง EOF ด้วย Ctrl-D นั่นเป็นอีกสิ่งหนึ่งที่โหมด canonical รับผิดชอบ คุณจะยังคงสามารถยกเลิกcatด้วย Ctrl-C ได้เนื่องจากอักขระที่สร้างสัญญาณถูกควบคุมโดยแฟล็กที่แยกต่างหาก ( stty rawหรือstty -isig)

ความลึกลับสำหรับฉันคือเหตุผลว่าเพราะคุณแสดงให้เห็นแล้วว่าคุณรู้xclipแล้วคุณไม่เพียง แต่ใช้xclip -o > fileแทนcat


1
ความลึกลับสามารถแก้ไขได้อย่างง่ายดาย: ดูเหมือนว่า artfulrobot ต้องการเติมไฟล์บนโฮสต์ระยะไกลด้วยข้อมูลจากคลิปบอร์ดอย่างรวดเร็ว ในเปลือกระยะไกลโดยปกติจะไม่มีการเข้าถึงคลิปบอร์ดท้องถิ่นโดยตรงผ่าน xclip
jofel

3
อ่าอัปโหลดโดยวางดี ถ้าฉันต้องทำอย่างใดอย่างหนึ่งและมันไม่ใช่ข้อความธรรมดาฉันจะ uuencode มันแทนที่จะพยายามโน้มน้าวให้คนขับรถ tty ผ่านมันไป ข้อความธรรมดาที่มีเส้นขนาดมหึมาก็สามารถจัดการได้เช่นกัน

2

ถ้าคุณทำ:

stty eol =

และเรียกใช้การสาธิตแนะของคุณแก้ไขคุณจะเห็นบาร์ fooในงานพิมพ์ของtest.out วินัยในสายการผลิตของเทอร์มินัลจะล้างออกไปยังเครื่องอ่านในขณะที่อ่านeol char แต่ละรายการในอินพุตของคุณ

เทอร์มินัลโหมดโหมดบัญญัติ - ตามที่สามารถกำหนดค่าด้วยstty icanonหรืออาจเป็นเพียงstty sane- จัดการอักขระอินพุตพิเศษต่อไปนี้ ...

  • EOF
    • ค่าเริ่มต้น: ^D
    • ยุติบรรทัดอินพุตและส่งเอาต์พุตไปยังตัวอ่าน เนื่องจากถูกลบออกจากอินพุตหากอินพุตเป็นอักขระตัวเดียวบนบรรทัดมันจะถูกส่งเป็นnullอ่าน - หรือสิ้นสุดไฟล์ - ไปยังตัวอ่าน
  • EOL
    • เริ่มต้น: ไม่ได้รับมอบหมาย
    • ยุติบรรทัดอินพุตด้วย แต่จะไม่ถูกลบออกจากอินพุต
  • ฆ่า
    • ค่าเริ่มต้น: ^U
    • ลบอินพุตบัฟเฟอร์ทั้งหมด
  • ลบ
    • ค่าเริ่มต้น: ^H (หรืออาจ@หรือ^?ในบางระบบ)
    • ลบอักขระอินพุตบัฟเฟอร์สุดท้าย

เมื่อiextenถูกตั้งค่าเช่น - stty icanon iextenหรืออาจเป็นอีกครั้งstty saneเทอร์มินัล Linux ที่เป็นที่ยอมรับก็จะจัดการ ...

  • eol2
    • ค่าเริ่มต้น: ไม่ได้กำหนด
    • นอกจากนี้ยังยุติบรรทัดอินพุตและยังไม่ถูกลบออกจากอินพุต
  • werase
    • ค่าเริ่มต้น: ^W
    • ลบสุดท้ายอินพุตบัฟเฟอร์คำ
  • rprnt
    • ค่าเริ่มต้น: ^R
    • พิมพ์อินพุตบัฟเฟอร์ทั้งหมดอีกครั้ง
  • lnext
    • ค่าเริ่มต้น: ^V
    • ลบความสำคัญเป็นพิเศษใด ๆ เท่าที่มีระเบียบวินัยในบรรทัดสำหรับอักขระอินพุตที่ตามมาทันที

ตัวละครเหล่านี้ได้รับการจัดการโดยการเอาพวกเขาจากการสตรีมใส่ - ยกเว้นEOLและeol2ที่เป็น - และการแสดงที่เกี่ยวข้องฟังก์ชั่นพิเศษก่อนที่จะผ่านกระแสการประมวลผลต่อผู้อ่าน - ซึ่งมักจะเป็นเปลือกของคุณ แต่อาจจะเป็นสิ่งที่กลุ่มกระบวนการเบื้องหน้าคือ .

อักขระอินพุตพิเศษอื่น ๆ ที่ได้รับการจัดการในทำนองเดียวกัน แต่สามารถกำหนดค่าได้อย่างอิสระจากการตั้งค่าicanonใด ๆรวมถึงชุดisig - set like stty isigและอาจรวมอยู่ในการกำหนดค่าsane :

  • เลิก
    • ค่าเริ่มต้น: ^\
    • ล้างอินพุตบัฟเฟอร์ทั้งหมด(หากไม่ได้ตั้งค่าnoflsh )และส่ง SIGQUIT ไปยังกลุ่มกระบวนการส่วนหน้า - อาจสร้างคอร์ดัล
  • susp
    • ค่าเริ่มต้น: ^Z
    • ล้างอินพุตบัฟเฟอร์ทั้งหมด(หากไม่ได้ตั้งค่าnoflsh )และส่ง SIGTSTP ไปยังกลุ่มกระบวนการส่วนหน้า กลุ่มกระบวนการที่ถูกระงับอาจกลับมาทำงานต่อได้ด้วยkill -CONT "$!"หรือfgในเชลล์ควบคุมงาน( set -m)
  • intr
    • ค่าเริ่มต้น: ^C
    • ล้างอินพุตบัฟเฟอร์ทั้งหมด(หากไม่ได้ตั้งค่าnoflsh )และส่ง SIGINT ไปยังกลุ่มกระบวนการส่วนหน้า

และชุดixon - กำหนดค่าเช่นเดียวกับstty ixonและมักจะรวมอยู่ในการตั้งค่าสติ :

  • หยุด
    • ค่าเริ่มต้น: ^S
    • หยุดเอาต์พุตทั้งหมดไปยังตัวอ่านจนกว่าจะเริ่มต้นการอ่านอินพุตหรือ - เมื่อตั้งค่าixany - อ่านอักขระอย่างน้อยหนึ่งตัว
  • เริ่มต้น
    • ค่าเริ่มต้น: ^Q
    • เอาท์พุทเตะถ้ามันได้รับก่อนหน้านี้หยุดหยุด
  • ทั้งหยุดและเริ่มต้นจะถูกลบออกจากอินพุตเมื่อประมวลผล แต่ถ้าเอาต์พุตถูกรีสตาร์ทเนื่องจากอักขระใด ๆ ในอินพุตเมื่อตั้งค่าixanyดังนั้นอักขระนั้นจะไม่ถูกลบออก

อักขระพิเศษที่จัดการกับระบบที่ไม่ใช่ Linux อื่น ๆ อาจรวมถึง ...

  • เปี่ยม
    • ค่าเริ่มต้น: ^O
    • สลับการทิ้งและการลบอินพุตบัฟเฟอร์และถูกลบออกจากอินพุต
  • dsusp
    • ค่าเริ่มต้น: ไม่ได้กำหนด
    • ล้างอินพุตบัฟเฟอร์ทั้งหมดเฉพาะเมื่อผู้อ่านอ่านอักขระอินพุตพิเศษที่กำหนดจากนั้นส่ง SIGTSTP

และอาจ ...

  • swtch
    • เริ่มต้น^@ (ความหมาย\0หรือNUL)
    • สวิทช์เบื้องหน้าเปลือกชั้น สำหรับใช้กับแอ็พพลิเคชันshl เชลล์เลเยอร์ในบางระบบ
    • การติดตั้งshlมัลติเพล็กซ์ ptys และดังนั้นจึงเข้ากันได้กับการควบคุมงานมากกว่าพฤติกรรมการพึ่งพาswtchของการติดตั้งใช้งานดั้งเดิมสามารถทำได้อย่างอิสระในheirloom-toolchestชุดเครื่องมือ

สำหรับภาพที่ชัดเจนของวิธีการและเหตุผล(และอาจจะทำไมไม่)man 3 termiosฟังก์ชั่นการป้อนข้อมูลเหล่านี้ได้รับการจัดการให้คำปรึกษา

ทุกฟังก์ชั่นดังกล่าวข้างต้นสามารถกำหนด(หรือพระราชเสาวนีย์) - เมื่อบังคับ - sttyfunction assigned-keyเช่น เพื่อปิดการใช้งานฟังก์ชั่นใด ๆ เดียว อีกวิธีหนึ่งคือความพยายามต่างๆที่มีการมอบหมายงานใด ๆ ของฟังก์ชั่นสายการแก้ไขดังกล่าวมีทั้งหมดของ GNU, AST หรือมรดกตกทอดของการใช้งานดูเหมือนจะแสดงให้คุณยังสามารถเป็นNULมอบหมายสำหรับการทำงานใด ๆ ที่ดูเหมือนว่าจะถือเอาการตั้งค่าให้ไม่ได้มอบหมายบน linux ของฉัน ระบบ.sttyfunction^-sttysttyfunction^@

อาจเป็นไปได้ว่าคุณเห็นเสียงสะท้อนของตัวละครเหล่านี้เมื่อคุณพิมพ์(ตามที่สามารถกำหนดค่าด้วย w / [-] ctlecho )แต่นี่เป็นเพียงเครื่องหมายที่จะแสดงให้คุณเห็นว่าคุณทำที่ไหน - โปรแกรมที่รับอินพุตของคุณไม่มีความคิดว่า พิมพ์พวกเขา(ยกเว้นeol [2]นั่นคือ)และรับเฉพาะสำเนาของอินพุตของคุณที่ระเบียบวินัยของบรรทัดใช้เอฟเฟกต์ของพวกเขา

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

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


1

catจะยอมรับอักขระจำนวนเท่าใดก็ได้ตามที่คุณสามารถเห็นได้ด้วยการทำตัวอย่างcat /dev/random > test.bin(อย่าทำจนกว่าคุณจะรู้วิธีหยุด :) ฉันพยายามคัดลอกและวางไฟล์ขนาดใหญ่cat > test.txtเข้าไป ทั้งหมดของเส้นที่สิ้นสุดลงในไฟล์ว่าฉันยกเลิกด้วยCtrl- cหรือCtrl- dแต่ในกรณีที่ไม่ได้ทุกสายถูกพิมพ์ไปยังสถานี สิ่งนี้ฉันเชื่อว่าเป็นเพราะcatบัฟเฟอร์การพิมพ์กำลังรอบัฟเฟอร์ที่สมบูรณ์ของข้อความหรืออินพุตโดยตรงจากเทอร์มินัลก่อนการพิมพ์แต่ละครั้ง

ในระบบของฉันฉันคิดว่าขนาดของบัฟเฟอร์คือ 4096 (2 ^ 12) ไบต์: สร้างไฟล์ 4095 ไบต์ใช้(printf '1234567890%.0s' {1..409} && printf 12345) > test.inโหลดที่เป็นสำเนา buffer ใช้xclip test.inเริ่มcat > test.outวางใช้Shift- Insertและยุติกระแสโดยการกด-Ctrl dตอนนี้เพิ่มไบต์ที่ใช้printf '6' >> test.inแล้วสตรีมจะถูกพิมพ์สองครั้ง : หนึ่งครั้งในcatเอาต์พุต (4096 ไบต์ทั้งหมด) และ4095 ไบต์สุดท้ายอีกครั้งบนเชลล์หลังจากยุติ


+1 ในกรณีของฉันมันขึ้นอยู่กับคลิปบอร์ดที่ใช้ ถ้าฉันใช้บัฟเฟอร์การเลือก (วางคลิกกลาง) ฉันเห็นเพียง 4542 บรรทัดแรกของข้อมูลทดสอบของฉัน (แต่ทั้งหมดนั้นลงเอยด้วยไฟล์ที่สร้าง) แต่ใช้คลิปบอร์ด X (Ctrl + C / Ctrl + V) ที่ฉันเห็น ทั้งหมดของมัน. ในทั้งสองกรณีข้อมูลทั้งหมดจะถูกพิมพ์ลงในไฟล์ผลลัพธ์ แต่ในข้อมูลบางส่วนเท่านั้นในอดีตถูกแสดงในเทอร์มินัล
terdon

1
ฉันไม่ได้รับพฤติกรรมเดียวกัน ดูคำถามที่แก้ไข
artfulrobot

0

ทางออกหนึ่งคือการวางลงในเครื่องมือแก้ไขที่รองรับเส้นยาวเช่น vim

หากคุณใช้ vim ให้เข้าสู่โหมดวาง:pasteก่อนด้วยก่อนเข้าสู่โหมดแทรกด้วยiและวางข้อความ

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