รายการอาร์กิวเมนต์ยาวเกินไปสำหรับ ls


48

ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อพยายามls *.txt | wc -lไดเรกทอรีที่มีไฟล์จำนวนมาก:

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

เกณฑ์ของ "รายการอาร์กิวเมนต์" นี้ขึ้นอยู่กับ distro หรือข้อมูลจำเพาะของคอมพิวเตอร์หรือไม่ โดยปกติแล้วฉันจะส่งผลให้เกิดผลลัพธ์ที่ยิ่งใหญ่เช่นคำสั่งอื่น ๆ ( wc -lตัวอย่าง) ดังนั้นฉันจึงไม่กังวลกับข้อ จำกัด ของเทอร์มินัล


6
ซึ่งนับว่าเป็นผลลัพธ์ของการแยกวิเคราะห์lsซึ่งเป็นความคิดที่ไม่ดีดังนั้นควรหลีกเลี่ยง สำหรับการนับดูวิธีที่ดีที่สุดในการนับจำนวนไฟล์ในไดเรกทอรีคืออะไร สำหรับวิธีแก้ปัญหาที่ยุ่งยากดูว่าทำไมการวนซ้ำจึงไม่ทำให้เกิดข้อผิดพลาด“ การโต้แย้งยาวเกินไป” .
ผลิต

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

คุณสามารถใช้ getconf ARG_MAX เพื่อ จำกัด ขีด จำกัด ของระบบที่ใช้ระบบปฏิบัติการยูนิกซ์ส่วนใหญ่
Prasanth

คำตอบ:


49

ข้อผิดพลาดข้อความของคุณรายการอาร์กิวเมนต์ยาวเกินไปมาจาก*ls *.txtของ

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

ไม่มีข้อ จำกัด ดังกล่าวกับขนาดท่อ ดังนั้นคุณสามารถออกคำสั่งนี้:

find -type f -name '*.txt'  | wc -l

หมายเหตุ: เมื่อวันที่ทันสมัยลินุกซ์, ตัวละครที่แปลกในชื่อไฟล์ (เช่นการขึ้นบรรทัดใหม่) จะหนีด้วยเครื่องมือเช่นlsหรือfindแต่ยังคงแสดงจาก* หากคุณใช้ระบบปฏิบัติการ Unix แบบเก่าคุณจะต้องใช้คำสั่งนี้

find -type f -name '*.txt' -exec echo \;  | wc -l

NB2: ฉันสงสัยว่าจะสร้างไฟล์ด้วยบรรทัดใหม่ในชื่อของมันได้อย่างไร ไม่ใช่เรื่องยากเมื่อคุณรู้เคล็ดลับ:

touch "hello
world"

1
ฉันแก้ไขมันเล็กน้อยเพื่อทำงานในกรณีที่มีชื่อไฟล์ที่มีบรรทัดใหม่ในพวกเขา คุณอาจต้องการเพิ่ม a -maxdepth 1หากคุณไม่ต้องการนับไฟล์ในไดเรกทอรีย่อย
Shawn J. Goff

-exec echo \;คุณไม่จำเป็นต้อง
Mikel

@ ShawnJ.Goff ฉันได้ทำการทดสอบแล้ว ไม่จำเป็นต้องมี 'echo' ใน GNU เวอร์ชันปัจจุบันค้นหา
Coren

@Coren @Mikel - ทุกคนไม่ได้ findGNU findบน OS X และระบบ busybox-based และฉันเดาระบบ BSD-based ใด ๆ ที่แสดงให้เห็นชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่ในนั้นซึ่งจะยุ่งกับการนับ
Shawn J. Goff

ฮะ? wc -lกำลังนับบรรทัดใหม่ ดังนั้นเราจึงต้องการให้มีการขึ้นบรรทัดใหม่
Mikel

11

ขึ้นอยู่กับเคอร์เนลเวอร์ชันของคุณเป็นหลัก

คุณควรจะเห็นขีด จำกัด ของระบบของคุณโดยการเรียกใช้

getconf ARG_MAX

ซึ่งบอกจำนวนสูงสุดของไบต์ที่บรรทัดคำสั่งสามารถมีได้หลังจากที่ถูกขยายโดยเชลล์

ใน Linux <2.6.23 ขีด จำกัด มักเป็น 128 KB

ใน Linux> = 2.6.25 ขีด จำกัด คือ 128 KB หรือ 1/4 ของขนาดสแต็กของคุณ (ดูulimit -s) แล้วแต่จำนวนใดจะใหญ่กว่า

ดูรายละเอียดทั้งหมดได้จากman page execve (2)


น่าเสียดายที่การวางท่อls *.txtจะไม่สามารถแก้ไขปัญหาได้เนื่องจากขีด จำกัด อยู่ในระบบปฏิบัติการไม่ใช่เชลล์

เชลล์ขยายตัว*.txtแล้วพยายามโทรออก

exec("ls", "a.txt", "b.txt", ...)

และคุณมีไฟล์จำนวนมากที่ตรงกับ*.txtที่คุณเกินขีด จำกัด 128 KB

คุณจะต้องทำอะไรบางอย่างเช่น

find . -maxdepth 1 -name "*.txt" | wc -l

แทน.

(และดูความคิดเห็นของ Shawn J. Goff ด้านล่างเกี่ยวกับชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่)


ขออภัยที่ไม่สามารถตอบคำถามได้ ต้องการชื่อเสียงมากขึ้น :( ขอบคุณทุกคน !!

คุณสามารถอธิบายสิ่งที่.และความ-maxdepth 1หมายในบรรทัดสุดท้าย? ขอบคุณ! : D
Guilherme Salomé

2
@ GuilhermeSalomé .หมายถึงไดเรกทอรีปัจจุบัน-maxdepth 1หมายความว่าไม่ได้ดูในไดเรกทอรีย่อย *.txtครั้งนี้มีวัตถุประสงค์เพื่อให้ตรงกับไฟล์เดียวกับ
Mikel

9

วิธีแก้ปัญหาอื่น:

ls | grep -c '\.txt$'

แม้ว่าจะlsผลิตออกมากกว่าls *.txtผลิต (หรือพยายามที่จะผลิต) ก็ไม่ได้วิ่งเข้าไปใน "อาร์กิวเมนต์ยาวเกินไปปัญหา" เพราะคุณไม่ได้ผ่านใด ๆlsข้อโต้แย้ง โปรดทราบว่าgrepใช้นิพจน์ปกติแทนรูปแบบการจับคู่ไฟล์

คุณอาจต้องการใช้:

ls -U | grep -c '\.txt$'

(สมมติว่าเวอร์ชั่นของคุณlsรองรับตัวเลือกนี้) สิ่งนี้บอกlsไม่ให้เรียงลำดับเอาต์พุตซึ่งสามารถประหยัดทั้งเวลาและหน่วยความจำ - และในกรณีนี้ลำดับไม่สำคัญเนื่องจากคุณเพิ่งนับไฟล์ ทรัพยากรที่ใช้ในการเรียงลำดับผลลัพธ์มักไม่สำคัญ แต่ในกรณีนี้เรารู้แล้วว่าคุณมี*.txtไฟล์จำนวนมาก

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


1

MAX_ARG_PAGES ดูเหมือนจะเป็นพารามิเตอร์เคอร์เนล การใช้findและxargsเป็นชุดค่าผสมทั่วไปเพื่อแก้ไขข้อ จำกัด นี้ แต่ฉันไม่แน่ใจว่าจะใช้งานwcได้หรือไม่

ไปป์ที่เอาต์พุตของfind . -name \*\.txtไฟล์และนับบรรทัดในไฟล์นั้นควรทำหน้าที่เป็นวิธีแก้ปัญหา


คุณสามารถทำอะไรกับlsผลลัพธ์ของมันจะไม่แก้ปัญหานี้ ตราบใดที่สัญลักษณ์ตัวแทน * .txt ถูกขยายเกินขีด จำกัด จะล้มเหลวก่อนที่จะเริ่มlsและสร้างผลลัพธ์ใด ๆ
ผลิต

จริงฉันได้อัพเดทคำตอบแล้ว
Bram

ดีกว่า แต่เพื่อให้สามารถแทนที่ได้lsคุณควรระบุ-maxdepth 1เพื่อหลีกเลี่ยงการสแกนไดเรกทอรีย่อยซ้ำ ๆ
ผลิต

ขออภัยที่ไม่สามารถตอบคำถามได้ ต้องการชื่อเสียงมากขึ้น :(

0

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

ls | grep jpg | <something>

ฉันได้รับรายชื่อยาว 90,000 รายการของ jpgs และส่งไปยัง avconv เพื่อสร้างช่วงเวลา

ก่อนหน้านี้ฉันใช้ ls * .jpg | avconv ก่อนที่ฉันจะพบปัญหานี้

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