“ รายการอาร์กิวเมนต์ยาวเกินไป”: ฉันจะจัดการกับมันได้อย่างไรโดยไม่เปลี่ยนคำสั่งของฉัน


18

เมื่อฉันเรียกใช้คำสั่งเช่นls */*/*/*/*.jpgฉันได้รับข้อผิดพลาด

-bash: /bin/ls: Argument list too long

ฉันรู้ว่าทำไมสิ่งนี้เกิดขึ้น: มันเป็นเพราะมีข้อ จำกัด เคอร์เนลกับจำนวนพื้นที่สำหรับการขัดแย้งกับคำสั่ง คำแนะนำมาตรฐานคือการเปลี่ยนคำสั่งที่ฉันใช้เพื่อหลีกเลี่ยงการต้องใช้พื้นที่มากสำหรับการขัดแย้ง (เช่นใช้findและxargs)

ถ้าฉันไม่ต้องการเปลี่ยนคำสั่งล่ะ? ถ้าฉันต้องการใช้คำสั่งเดียวกันต่อไป ฉันจะทำสิ่งต่าง ๆ "แค่ทำงาน" โดยไม่ได้รับข้อผิดพลาดนี้ได้อย่างไร มีโซลูชั่นอะไรบ้าง?


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

1
@ jw013 ตามรุ่นของเคอร์เนล linux อาจเป็นไปได้ที่จะเพิ่มรายการอาร์กิวเมนต์ - ดูunix.stackexchange.com/a/45161/8979สำหรับรายละเอียดเกี่ยวกับการเปลี่ยนแปลงในระบบล่าสุด
Ulrich Dangel

@UlrichDangel ใช่แล้วมันเป็นไปได้! ดูคำตอบของฉัน; คำตอบของฉันแสดงให้เห็นว่าต้องทำอย่างไร (บน Linux ด้วยเคอร์เนลที่เพียงพอล่าสุด)
DW

คำตอบ:


26

บน Linux จำนวนพื้นที่สูงสุดสำหรับอาร์กิวเมนต์คำสั่งคือ 1 / 4th ของจำนวนพื้นที่สแต็กที่มีอยู่ ดังนั้นทางออกคือการเพิ่มปริมาณพื้นที่ว่างสำหรับกองซ้อน

รุ่นสั้น: เรียกใช้บางสิ่งบางอย่างเช่น

ulimit -s 65536

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

$ ulimit -s
8192

เลือกตัวเลขที่มีขนาดใหญ่ขึ้นและกำหนดจำนวนพื้นที่ว่างสำหรับสแต็ก ตัวอย่างเช่นหากคุณต้องการลองอนุญาตสแต็กสูงสุด 65536 KB ให้รันสิ่งนี้:

$ ulimit -s 65536

คุณอาจต้องลองเล่นดูว่ามันต้องมีขนาดใหญ่แค่ไหนโดยใช้การลองผิดลองถูก ในหลายกรณีนี้เป็นวิธีที่รวดเร็วและสกปรกที่จะขจัดความจำเป็นในการแก้ไขคำสั่งและการทำงานออกไวยากรณ์ของfind, xargsฯลฯ (แม้ว่าฉันตระหนักดีมีประโยชน์อื่น ๆ ที่จะทำเช่นนั้น)

ฉันเชื่อว่านี่เป็น Linux เฉพาะ ฉันสงสัยว่าอาจจะไม่ช่วยในระบบปฏิบัติการ Unix อื่น ๆ (ไม่ได้ทดสอบ)


1
คุณสามารถตรวจสอบสิ่งนี้ได้: $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Alex

2

นี้บทความวารสารลินุกซ์จะช่วยให้การแก้ปัญหา 4 เฉพาะโซลูชันที่สี่เท่านั้นที่ไม่เกี่ยวข้องกับการเปลี่ยนคำสั่ง:

วิธีที่ # 4 เกี่ยวข้องกับการเพิ่มจำนวนหน้าที่ถูกจัดสรรภายในเคอร์เนลสำหรับอาร์กิวเมนต์บรรทัดคำสั่งด้วยตนเอง หากคุณดูที่ไฟล์ include / linux / binfmts.h คุณจะพบสิ่งต่อไปนี้ใกล้ด้านบน:

/*
 * MAX_ARG_PAGES defines the number of pages allocated for   arguments
 * and envelope for the new program. 32 should suffice, this gives
 * a maximum env+arg of 128kB w/4KB pages!
 */
#define MAX_ARG_PAGES 32

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

ในระบบทดสอบของฉันเองฉันจัดการเพื่อแก้ปัญหาทั้งหมดของฉันโดยการเพิ่มค่านี้เป็น 64 หลังจากการทดสอบที่ครอบคลุมฉันไม่ได้พบปัญหาเดียวตั้งแต่เปลี่ยน สิ่งนี้คาดว่าจะเกิดขึ้นทั้งหมดแม้จะMAX_ARG_PAGESตั้งไว้ที่ 64 บรรทัดคำสั่งที่ยาวที่สุดที่ฉันสามารถผลิตได้จะใช้หน่วยความจำระบบ 256KB เท่านั้นซึ่งไม่มากตามมาตรฐานฮาร์ดแวร์ระบบในปัจจุบัน

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

ฉันยอมรับว่าข้อ จำกัด นั้นน่ารำคาญอย่างยิ่ง


1

แทนที่จะls */*/*/*/*.jpgลอง:

echo */*/*/*/*.jpg | xargs ls

xargs(1) รู้ว่าอะไรคือจำนวนอาร์กิวเมนต์สูงสุดที่อยู่ในระบบและจะแยกอินพุตมาตรฐานเพื่อเรียกบรรทัดคำสั่งที่ระบุหลาย ๆ ครั้งโดยไม่มีการขัดแย้งมากกว่าขีด จำกัด นั้น ๆ สิ่งที่มันเป็น (คุณสามารถตั้งให้ต่ำกว่า สูงสุดของระบบปฏิบัติการโดยใช้-nตัวเลือก)

ตัวอย่างเช่นสมมติว่าขีด จำกัด คือ 3 ข้อโต้แย้งและคุณมีห้าไฟล์ ในกรณีxargsนั้นจะทำงานlsสองครั้ง:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

บ่อยครั้งนี้มีความเหมาะสมอย่างสมบูรณ์แบบ แต่ก็ไม่เสมอ - ตัวอย่างเช่นคุณไม่สามารถพึ่งพาls(1) การเรียงลำดับทั้งหมดของรายการสำหรับคุณอย่างถูกต้องเพราะแต่ละแยกต่างหากls-invocation xargsจะเรียงลำดับเฉพาะชุดย่อยของรายการที่กำหนดให้โดย

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


ขอบคุณสำหรับความคิด! นี่ไม่ใช่วิธีแก้ปัญหาที่ไม่ดี คำเตือนสองข้อ: 1. สิ่งนี้จะแบ่งไดเรกทอรีและชื่อไฟล์ที่มีช่องว่างในชื่อของพวกเขาดังนั้นจึงไม่ใช่สิ่งทดแทนที่สมบูรณ์แบบ 2. คือว่าจะไปทำงานเป็นปัญหาเดียวกันกับArgument list too longแต่สำหรับechoแทนlsบนเปลือกหอยที่echoไม่ได้เป็นเปลือกในตัวคำสั่ง? (อาจไม่ใช่ปัญหาในเชลล์ส่วนใหญ่ดังนั้นอาจไม่เกี่ยวข้องเลย)
DW

1
ใช่ตัวละครพิเศษในชื่อไฟล์เป็นปัญหา ทางออกที่ดีที่สุดของคุณคือใช้findกับเพรดิเคต-print0และส่งออกไปxargsพร้อมกับ-0ตัวเลือก echoเป็นเชลล์ในตัวและไม่ได้รับผลกระทบจากการ จำกัด บรรทัดคำสั่งของexec(3)
มิคาอิลต.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.