บรรทัดคำสั่ง Bash และขีด จำกัด อินพุต


91

มีการ จำกัด จำนวนอักขระที่กำหนดไว้ใน bash (หรือเชลล์อื่น ๆ ) สำหรับระยะเวลาในการป้อนข้อมูลหรือไม่? ถ้าเป็นเช่นนั้นจำนวนอักขระสูงสุดคืออะไร?

คือเป็นไปได้ไหมที่จะเขียนคำสั่งใน bash ที่ยาวเกินกว่าที่บรรทัดคำสั่งจะดำเนินการได้? หากไม่มีขีด จำกัด ที่กำหนดมีข้อ จำกัด ที่แนะนำหรือไม่?


2
อินพุตจำกัด เป็นความแตกต่างจากการโต้แย้ง OS ระดับขีด จำกัด (ทราบว่าบางสิ่งบางอย่างอื่นนอกเหนือจากข้อโต้แย้งเช่นตัวแปรสภาพแวดล้อมมีผลต่อการที่หนึ่ง) คำสั่งที่สร้างส่งผ่านไปยังระบบปฏิบัติการสามารถมีอักขระมากกว่าหรือน้อยกว่าคำสั่งเชลล์ที่สร้างขึ้น
Charles Duffy

คำตอบ:


129

ขีดจำกัดความยาวของบรรทัดคำสั่งไม่ได้ถูกกำหนดโดยเชลล์ แต่โดยระบบปฏิบัติการ โดยปกติขีด จำกัด นี้จะอยู่ในช่วงร้อยกิโลไบต์ POSIX หมายถึงขีด จำกัด นี้ARG_MAXและบนระบบที่สอดคล้องกับ POSIX คุณสามารถสอบถามได้

$ getconf ARG_MAX    # Get argument limit in bytes

เช่นใน Cygwin นี่คือ 32000 และใน BSDs และระบบ Linux อื่นที่ฉันใช้อยู่ที่ใดก็ได้ตั้งแต่ 131072 ถึง 2621440

หากคุณต้องการการประมวลผลรายการของไฟล์ที่เกินขีด จำกัด นี้คุณอาจต้องการที่จะมองไปที่xargsยูทิลิตี้ซึ่งเรียกโปรแกรมที่ซ้ำ ๆ ARG_MAXกับส่วนหนึ่งของข้อโต้แย้งไม่เกิน

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

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


คำตอบที่ดี แต่ฉันต้องการคำชี้แจง ถ้าฉันมีโครงสร้างcmd <<< "$LONG_VAR"และค่า LONG_VAR เกินขีด จำกัด มันจะระเบิดคำสั่งของฉันหรือไม่
Krzysztof Jabłoński

1
@ KrzysztofJabłońskiไม่น่าเป็นไปได้เพราะเนื้อหาของLONG_VARจะถูกส่งต่อไปยัง stdin - และทำทั้งหมดในเชลล์ มันไม่ได้ถูกขยายเป็นอาร์กิวเมนต์cmdดังนั้นขีด จำกัด ARG_MAX สำหรับ fork () / exec () จะไม่เข้ามามีบทบาท เป็นเรื่องง่ายที่จะลองด้วยตัวเอง: สร้างตัวแปรที่มีเนื้อหาเกิน ARG_MAX และรันคำสั่งของคุณ
Jens

2
นี่คือคำชี้แจงสำหรับบันทึก: สำหรับไฟล์ m4a ขนาด 8 เมกะไบต์ฉันทำ: blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null. หมายเหตุไม่มีข้อผิดพลาด
Mike S

4
ข้อแม้เล็กน้อย ตัวแปรสภาพแวดล้อมยังนับ sysconf manpage > เป็นการยากที่จะใช้ ARG_MAX เนื่องจากไม่ได้ระบุจำนวน> ของพื้นที่อาร์กิวเมนต์สำหรับ exec (3) ที่ใช้โดยตัวแปรสภาพแวดล้อม> ของผู้ใช้
Gerrit

3
@ user188737 ฉันรู้สึกเหมือนมันเป็นข้อแม้ใหญ่สวยในข้อบกพร่อง ยกตัวอย่างเช่นxargsใน MacOS 10.12.6 ขีด จำกัด เท่าใดก็พยายามที่จะใส่ในหนึ่งไปexec() ARG_MAX - 4096ดังนั้นการใช้สคริปต์xargsอาจใช้งานได้จนกระทั่งวันหนึ่งมีคนใส่สิ่งต่างๆมากเกินไปในสภาพแวดล้อม พบกับสิ่งนี้ในขณะนี้ (แก้ไขปัญหาด้วยxargs -s ???:)
neuralmer

45

โอเคพลเมือง ดังนั้นฉันจึงยอมรับขีดจำกัดความยาวบรรทัดคำสั่งเป็นพระกิตติคุณมาระยะหนึ่งแล้ว แล้วจะทำอย่างไรกับสมมติฐานของตน? ตรวจสอบตามธรรมชาติ

ฉันมีเครื่อง Fedora 22 พร้อมจำหน่าย (หมายถึง: Linux พร้อม bash4) ฉันได้สร้างไดเร็กทอรีที่มี 500,000 inodes (ไฟล์) ในแต่ละไฟล์มีความยาว 18 อักขระ ความยาวบรรทัดคำสั่งคือ 9,500,000 อักขระ สร้างขึ้นดังนี้:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

และเราทราบ:

$ getconf ARG_MAX
2097152

อย่างไรก็ตามโปรดทราบว่าฉันสามารถทำได้:

$ echo * > /dev/null

แต่สิ่งนี้ล้มเหลว:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

ฉันสามารถเรียกใช้ลูป:

$ for f in *; do :; done

ซึ่งเป็นเปลือกหอยอื่นในตัว

อ่านระมัดระวังของเอกสารสำหรับARG_MAXรัฐ, ความยาวสูงสุดของการโต้แย้งกับการทำงาน exec ซึ่งหมายความว่า: โดยไม่ต้องโทรexecก็ไม่มีARG_MAXข้อ จำกัด ดังนั้นจึงจะอธิบายว่าทำไม builtins เปลือกจะไม่ถูก จำกัด ARG_MAXโดย

และแน่นอนฉันสามารถlsไดเร็กทอรีของฉันได้หากรายการอาร์กิวเมนต์ของฉันยาว 1,09948 ไฟล์หรือประมาณ 2,089,000 อักขระ (ให้หรือรับ) เมื่อฉันเพิ่ม 18 ตัวอักษรไฟล์อีกหนึ่งชื่อไฟล์ แต่แล้วฉันจะได้รับรายการอาร์กิวเมนต์ยาวเกินไปข้อผิดพลาด ดังนั้นARG_MAXคือการทำงานตามที่โฆษณา: exec มีความล้มเหลวที่มีมากกว่าARG_MAXตัวอักษรบนอาร์กิวเมนต์ list- รวมทั้งก็ควรจะตั้งข้อสังเกตข้อมูลสภาพแวดล้อม


อืม. ฉันไม่ได้อ่านคำตอบที่มีอยู่เพื่อบอกเป็นนัยว่าบิวด์อินนั้นอยู่ภายใต้ข้อ จำกัด ที่เป็นปัญหา แต่สามารถดูได้อย่างแน่นอนว่ามีคนทำได้อย่างไร
Charles Duffy

6
ใช่ฉันคิดว่ามันยากที่จะจำ - โดยเฉพาะอย่างยิ่งสำหรับ afficianados บรรทัดคำสั่งที่ใหม่กว่า - สถานการณ์ของการเรียก bash builtin เทียบกับ fork / exec'ing คำสั่งนั้นแตกต่างกันในรูปแบบที่ไม่ชัดเจน ฉันต้องการทำให้ชัดเจน คำถามหนึ่งที่ฉันมักจะได้รับในการสัมภาษณ์งาน (ในฐานะ Linux Sysadmin) คือ "ฉันมีไฟล์จำนวนมากในไดเร็กทอรีฉันจะวนซ้ำไฟล์ทั้งหมดได้อย่างไร ... " ผู้ถามมักจะขับรถต่อแถว ขีดจำกัดความยาวและต้องการโซลูชัน find / while หรือ xargs ในอนาคตฉันจะพูดว่า "อ่านรก - แค่ใช้ห่วงมันจัดการได้!" :-)
Mike S

@MikeS ในขณะที่คุณสามารถทำลูปได้หากคุณสามารถใช้คำสั่งผสม find-xargs คุณจะแยกน้อยลงมากและจะเร็วขึ้น ;-)
Lester Cheung

4
@LesterCheung for f in *; do echo $f; doneจะไม่แยกเลย (builtins ทั้งหมด) ดังนั้นฉันไม่รู้ว่าคอมโบ find-xargs จะเร็วขึ้น ยังไม่ได้รับการทดสอบ อันที่จริงฉันไม่รู้ว่าชุดปัญหาของ OP คืออะไร อาจfind /path/to/directoryจะไม่มีประโยชน์กับเขาเพราะมันจะคืนชื่อพา ธ ของไฟล์ บางทีเขาอาจชอบความเรียบง่ายของการfor f in *วนซ้ำ ไม่ว่าการสนทนาจะเกี่ยวกับขีด จำกัด การป้อนข้อมูลบรรทัดไม่ใช่ประสิทธิภาพ มาดูหัวข้อกันดีกว่าซึ่งเกี่ยวข้องกับความยาวบรรทัดคำสั่ง
Mike S

FWIW ปัญหาอย่างที่ฉันจำได้คือแค่พยายามเขียนเชลล์ใน C และกำหนดระยะเวลาที่ฉันควรอนุญาตให้อินพุตเป็น
Derek Halden

-3

มีขีด จำกัด บัฟเฟอร์บางอย่างเช่น 1024 การอ่านจะหยุดการวางหรือการป้อนข้อมูลลงกลาง ในการแก้ปัญหานี้ให้ใช้ตัวเลือก -e

http://linuxcommand.org/lc3_man_pages/readh.html

- ใช้ Readline เพื่อรับบรรทัดในเชลล์แบบโต้ตอบ

เปลี่ยนการอ่านของคุณเป็นอ่าน -e และการป้อนข้อมูลบรรทัดที่น่ารำคาญหายไป


1
สิ่งนี้ไม่เกี่ยวกับread: "เช่นเป็นไปได้ไหมที่จะเขียนคำสั่งใน bash ที่ยาวเกินกว่าที่บรรทัดคำสั่งจะดำเนินการ"
Chai T. Rex

@ ChaiT.Rex คุณเรียงลำดับถูกต้อง แต่นี่คือสิ่งที่: ลองเรียกใช้ Bash แบบโต้ตอบโดยไม่ใช้ Readline กล่าวคือbash --noeditingและเมื่อพร้อมต์ใหม่ลองเรียกใช้คำสั่งecho somereallylongwordโดยที่ somereallylongword ยาวกว่า 4090 อักขระ พยายามบน Ubuntu 18.04 คำถูกตัดทอนดังนั้นเห็นได้ชัดว่ามีบางอย่างเกี่ยวกับ Readline ที่ไม่ได้เปิดใช้งาน
Amir

@Amir น่าสนใจ! คุณถูก! ฉันพยายามแก้ไขคำตอบ แต่แล้วฉันก็รู้ว่าตัวเลือก -e ใช้ไม่ได้กับ bash ในบริบทนี้ (ใน bash มันออกจากเชลล์ทันทีเมื่อเกิดข้อผิดพลาด) และฉันไม่แน่ใจว่าทำไมพอลถึงหันมาอ่าน อย่างไรก็ตามมีการ จำกัด บัฟเฟอร์ระหว่าง 4-5000 อักขระเมื่อ bash เริ่มต้นด้วย --noreadline นั่นเป็นผลข้างเคียงที่ฉันไม่รู้หรือคาดหวัง
Mike S
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.