ผลลัพธ์ของ ls *, ls ** และ ls ***


86

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

คำตอบ:


155

lsแสดงรายการไฟล์และเนื้อหาของไดเรกทอรีที่มันถูกส่งผ่านเป็นข้อโต้แย้งและหากไม่ได้รับข้อโต้แย้งมันจะแสดงรายการไดเรกทอรีปัจจุบัน นอกจากนี้ยังสามารถส่งผ่านตัวเลือกจำนวนมากที่มีผลต่อพฤติกรรมของมัน (ดูman lsรายละเอียด)

หากlsมีการส่งผ่านอาร์กิวเมนต์ที่เรียกว่า*มันจะค้นหาไฟล์หรือไดเรกทอรีที่เรียกว่า*ในไดเรกทอรีปัจจุบันและรายการมันเหมือนกัน lsไม่ได้ปฏิบัติต่อ*ตัวละครในลักษณะอื่นใดนอกจากตัวละครอื่น

แต่ถ้าls *เป็นเปลือกบรรทัดคำสั่งแล้วเปลือกจะขยายตัวที่*เป็นไปตามเปลือกที่สอดคล้องกันของglobbing (ยังเรียกว่าชื่อไฟล์การสร้างหรือขยายชื่อไฟล์ ) กฎ

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

ตัวอย่างเช่นถ้าไดเรกทอรีปัจจุบันมีไฟล์ที่เรียกว่า., .., .foo, -lและfoo bar, *จะได้รับการขยายตัวเปลือกสองข้อโต้แย้งที่จะส่งผ่านไปยังls: -lและfoo barดังนั้นมันจะเป็นกรณีที่คุณพิมพ์:

ls -l "foo bar"

หรือ

'ls' "-l" foo\ bar

ซึ่งมีสามวิธีในการเรียกใช้คำสั่งเดียวกันทั้งหมด ในทั้ง 3 กรณีlsคำสั่ง (ซึ่งอาจจะถูกเรียกใช้จาก/bin/lsการค้นหาของไดเรกทอรีที่กล่าวถึงใน$PATH) จะถูกส่งผ่าน 3 อาร์กิวเมนต์เหล่านี้: "ls", "-l" และ "foo bar"

ในกรณีนี้ในกรณีนี้lsจะถือว่าเป็นตัวเลือกแรก (พูดอย่างเคร่งครัดที่สอง ) เป็นตัวเลือก

ตอนนี้อย่างที่ฉันพูดเปลือกหอยต่าง ๆ มีโอเปอเรเตอร์กลมที่ต่างกัน เมื่อไม่กี่ทศวรรษที่ผ่านมาzshแนะนำตัว**/ดำเนินการ¹ซึ่งหมายถึงการจับคู่กับไดเรกทอรีย่อยระดับใด ๆ ซึ่งย่อมาจาก(*/)#และ***/เหมือนกัน

ไม่กี่ปีที่ผ่านมา (กรกฏาคม 2546, ksh93o+) ksh93ตัดสินใจที่จะคัดลอกพฤติกรรมนั้น แต่ตัดสินใจที่จะทำให้มันเป็นตัวเลือกและครอบคลุมเฉพาะ**กรณี (ไม่***) ในขณะที่**อยู่คนเดียวไม่ได้พิเศษในzsh(เพียงหมายถึงเช่นเดียวกับ*ในเปลือกแบบดั้งเดิมอื่น ๆ เนื่องจาก**หมายถึงจำนวนตัวอักษรใด ๆ ตามด้วยจำนวนตัวอักษรใด ๆ ) ใน ksh93 **หมายถึงเช่นเดียวกับ**/*(ดังนั้นไฟล์หรือไดเรกทอรีใด ๆ ด้านล่างปัจจุบัน (ไม่รวมไฟล์ที่ซ่อนอยู่)

bashคัดลอกksh93ไม่กี่ปีต่อมา (กุมภาพันธ์ 2009, ทุบตี 4.0), ด้วยไวยากรณ์เดียวกัน แต่ความแตกต่างที่โชคร้าย: ทุบตี**เป็นเหมือนzsh's ***, นั่นคือมันเป็นไปตาม symlink เมื่อ recursing ลงในไดเรกทอรีย่อยซึ่งโดยทั่วไปไม่ใช่สิ่งที่คุณต้องการและ สามารถมีผลข้างเคียงที่น่ารังเกียจ มันได้รับการแก้ไขบางส่วนใน bash-4.3 ใน symlink นั้นยังคงตามมา แต่การเรียกซ้ำหยุดลงที่นั่น มันได้รับการแก้ไขอย่างสมบูรณ์ใน 5.0

yashเพิ่ม**ในเวอร์ชัน 2.0 ในปี 2008 เปิดใช้งานด้วยextended-globตัวเลือก การติดตั้งใช้งานได้ใกล้ชิดกับzshสิ่งที่**อยู่คนเดียวไม่มากเป็นพิเศษ ในรุ่น 2.15 (2009) มันเพิ่ม***เหมือนในzshและสองของนามสกุลของตัวเอง.**และ.***จะรวม dirs ซ่อนไว้เมื่อ recursing (ในzshการD คัดเลือก glob (ใน**/*(D)) จะพิจารณาไฟล์ที่ซ่อนและไดเรกทอรี แต่ถ้าคุณเพียงต้องการที่จะสำรวจที่ซ่อนอยู่ dirs แต่ไม่ขยายไฟล์ที่ซ่อนอยู่คุณต้องการ((*|.*)/)#*หรือ**/[^.]*(D))

เปลือกปลา**นอกจากนี้ยังสนับสนุน เช่นเดียวกับรุ่นก่อนหน้านี้bashมันจะติดตาม symlink เมื่อลดระดับทรีไดเรกทอรี ในเปลือกที่ แต่ไม่ได้เช่นเดียวกับ**/* เป็นส่วนขยายที่สามารถขยายได้หลายไดเรกทอรี ใน, จะตรงแต่ไม่ขณะที่จะตรงและและ's เช่นจะต้องมีการเขียน ที่นั่นเป็นที่เข้าใจกันตามมาด้วยเพื่อให้เช่นเดียวกับ*****fish**/*.ca/b/c.ca.ca**.ca.cab/c/d.czsh**/.*.* **/.*********

tcshยังเพิ่มglobstarตัวเลือกใน V6.17.01 (พฤษภาคม 2010) และให้การสนับสนุนทั้งใน**และอาหาร***zsh

ดังนั้นในtcsh, bashและksh93, (เมื่อตัวเลือกที่สอดคล้องกันถูกเปิดใช้งาน ( globstar)) หรือfish, **ขยายทุกไฟล์และไดเรกทอรีดังต่อไปนี้อย่างใดอย่างหนึ่งในปัจจุบันและ***เป็นเช่นเดียวกับ**สำหรับfishการ symlink ภายใน**สำหรับtcshด้วยglobstarและเช่นเดียวกับ*ในbashและksh93(แม้ว่ามันจะเป็น ไม่เป็นไปไม่ได้ที่เวอร์ชั่นในอนาคตของเชลล์เหล่านั้นจะทำการสำรวจ symlink ด้วย)

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

ls -- *

หรือ:

ls ./*

มีคำสั่งบางอย่าง (มันไม่สำคัญสำหรับls) ที่สองที่เป็นที่นิยมเพราะแม้จะมี--ชื่อไฟล์บางอย่างอาจได้รับการปฏิบัติเป็นพิเศษ เป็นกรณีของ-โปรแกรมอรรถประโยชน์ข้อความส่วนใหญ่cdและpushdและชื่อไฟล์ที่มี=อักขระawkเป็นตัวอย่าง prepending ./ข้อโต้แย้งทั้งหมดเอาความหมายพิเศษของพวกเขา (อย่างน้อยสำหรับกรณีดังกล่าวข้างต้น)

ควรสังเกตว่าเชลล์ส่วนใหญ่มีตัวเลือกจำนวนมากที่มีผลต่อพฤติกรรมการวนรอบ (เช่นว่าไฟล์จุดถูกละเว้นหรือไม่ลำดับการเรียงลำดับจะทำอย่างไรถ้าไม่มีคู่ที่ตรงกัน ... ) ดู$FIGNOREพารามิเตอร์ในksh

นอกจากนี้ในทุกเปลือก แต่csh, tcsh, fishและzshถ้ารูปแบบ globbingไม่ตรงกับไฟล์ใด ๆ รูปแบบจะถูกส่งเป็นข้อโต้แย้งที่ไม่ได้ขยายซึ่งทำให้เกิดความสับสนและอาจจะเป็นข้อบกพร่อง ตัวอย่างเช่นหากไม่มีไฟล์ที่ไม่ถูกซ่อนอยู่ในไดเรกทอรีปัจจุบัน

ls *

จะเรียกจริงlsกับทั้งสองมีปากเสียงและls *และเนื่องจากไม่มีไฟล์เลยดังนั้นจึงไม่มีใครเรียก*คุณจะเห็นข้อความแสดงข้อผิดพลาดจากls (ไม่ใช่เชลล์) เช่น: ls: cannot access *: No such file or directoryซึ่งเป็นที่รู้กันว่าทำให้คนคิดว่ามันเป็นการlsขยายความจริง

ปัญหานั้นเลวร้ายยิ่งกว่าในกรณีเช่น:

rm -- *.[ab]

ถ้าไม่มี*.aหรือ*.bไฟล์ในไดเรกทอรีปัจจุบันแล้วคุณอาจจบลงด้วยการลบไฟล์ที่เรียกว่า*.[ab]ด้วยความผิดพลาด ( csh, tcshและzshจะรายงานไม่ตรงกับความผิดพลาดและจะไม่เรียกrm(และfishไม่สนับสนุน[...]สัญลักษณ์))

หากคุณไม่ต้องการที่จะผ่านตัวอักษร*เพื่อlsคุณจะต้องพูดว่า*ตัวละครในทางใดทางหนึ่งเช่นเดียวกับในls \*หรือหรือls '*' ls "*"ในเชลล์ที่มีลักษณะคล้าย POSIX สามารถปิดการใช้งานแบบกลมได้โดยใช้set -o noglobหรือset -f(สิ่งหลังไม่ทำงานzshยกเว้นในsh/ kshจำลอง)


¹ในขณะที่(*/)#ได้รับการสนับสนุนเสมอมันเป็นครั้งแรกที่สั้น..../ใน zsh-2.0 (และอาจมาก่อน) จากนั้น****/ใน 2.1 ก่อนที่จะได้รับรูปแบบที่ชัดเจน**/ใน 2.2 (ต้นปี 1992)


22
คำตอบที่ดีจริงๆ!
Andrea Corbellini

7
find -name *อีกตัวอย่างที่ดีคือ findโดยเฉพาะอย่างยิ่งที่มีรูปแบบที่ซับซ้อนมากขึ้นถ้ามีเป็นสิ่งหนึ่งในการแข่งขันในไดเรกทอรีปัจจุบันคนมักจะไม่ได้ตระหนักว่าพวกเขาไม่ได้ผ่านดอกจันไป
njsg

ฉันให้ +1 ต่อไปฉันดีใจจริงๆที่เห็น Stephane Chazelas เปิดใช้งานที่นี่ในunix.stackexchange.com ! ผลงานยอดเยี่ยมสเตฟานก็เช่นเคย!
Dimitre Radoulov

1
ในปลาจะพยายามที่จะลบทุกอย่างจบลงด้วย*.[ab] ไม่ได้เป็นพิเศษในปลา .[ab][
Konrad Borowski

35

คำสั่งlsเริ่มต้นที่ls .: รายชื่อรายการทั้งหมดในไดเรกทอรีปัจจุบัน

คำสั่งls *หมายถึง 'run ls ในการขยาย*รูปแบบเชลล์'

รูปแบบการประมวลผลโดยเปลือกและขยายไปยังรายการทั้งหมดในไดเรกทอรีปัจจุบันยกเว้นผู้ที่เริ่มต้นด้วย* .มันจะลึกลงไปหนึ่งระดับ

การตีความของ*รูปแบบสองหรือสามขึ้นอยู่กับเปลือกที่ใช้จริง

*เป็นอักขระตัวแทนที่ตรงกับอักขระตั้งแต่ 0 ตัวขึ้นไป กระสุนสมัยใหม่บางตัวจะถูกย่อเก็บลงในไดเรกทอรีย่อยเมื่อเห็น**รูปแบบ


17
ยกเว้นว่า* จะเพิ่มบางอย่างพิเศษดูคำตอบอื่น ๆ อธิบาย globstar มันควรจะชัดเจนว่า ls ไม่เกี่ยวข้องกับเครื่องหมายดอกจันมันไม่เคยผ่านเครื่องหมายดอกจันเหล่านี้เลย เรียกใช้เพื่อดูสิ่งที่จะได้รับการดำเนินการเมื่อคุณเขียนecho ls * ls *
njsg

12

คุณสามารถเข้าใจขั้นตอนทั้งหมดได้อย่างชัดเจนโดยพิมพ์echoแทนlsคำสั่งแรกเพื่อดูว่าคำสั่งขยายไปที่:

$ echo *
Applications Downloads Documents tmp.html

ดังนั้นในกรณีนี้ls *ขยายไปls Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

ดังนั้นไม่มีการเปลี่ยนแปลง สิ่งนี้ถือว่าคุณใช้bashเป็นเชลล์ของคุณ - คนส่วนใหญ่และเชลล์ที่แตกต่างกันมีพฤติกรรมที่แตกต่างกัน หากคุณกำลังใช้ashหรือcshหรือkshหรือzshคุณอาจคาดหวังว่าสิ่งต่าง ๆ จะทำงานแตกต่างกัน นั่นคือจุดที่มีกระสุนแตกต่างกัน

ลองทำสิ่งที่แตกต่างกัน (ยังกับbash) เพื่อให้เราได้แนวคิดของ*โอเปอเรเตอร์กลม ( ) ที่สามารถทำเพื่อเราได้ ตัวอย่างเช่นเราสามารถกรองตามชื่อ:

$ echo D*
Downloads Documents

และที่น่าสนใจ Trailing Slash เป็นส่วนหนึ่งของชื่อไดเรกทอรีใด ๆ ดังนั้น*/จะให้เฉพาะไดเรกทอรี (และลิงก์สัญลักษณ์ไปยังไดเรกทอรี):

$ echo */
Applications/ Downloads/ Documents/

และเราสามารถทำการกรองได้หลายระดับด้วยการใส่เครื่องหมายสแลชตรงกลาง:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

เนื่องจากDownloadsไดเรกทอรีไม่มีไดเรกทอรีย่อยจึงไม่สิ้นสุดในผลลัพธ์ สิ่งนี้มีประโยชน์มากสำหรับการตรวจสอบไฟล์ที่คุณต้องการ ฉันใช้คำสั่งเช่นนี้ตลอดเวลา:

$ ls -l /home/*/public_html/wp-config.php

รายการนี้หากมีwp-config.phpไฟล์ทั้งหมดที่มีอยู่ในระดับฐานของpublic_htmlไดเรกทอรีของผู้ใช้ใด ๆ หรืออาจจะสมบูรณ์มากขึ้น:

$ find /home/*/public_html/ -name wp-config.php

นี้จะพบใด ๆwp-config.phpไฟล์ในผู้ใช้ใด ๆpublic_htmlไดเรกทอรีหรือใด ๆ ของไดเรกทอรีย่อยของพวกเขา แต่มันจะทำงานอย่างมีประสิทธิภาพมากขึ้นกว่าเพียงแค่find /home/ -name wp-config.phpเพราะมันจะไม่ตรวจสอบอะไรแต่public_htmlไดเรกทอรีสำหรับแต่ละผู้ใช้


1
"นี่ถือว่าคุณใช้bashเป็นเปลือกของคุณ" ←และไม่ได้เปิดใช้งาน globstar shopt -s globstarและลองอีกครั้ง ...
njsg

อีกวิธีหนึ่งในการ demystify คือการset -xเริ่มพิมพ์คำสั่ง "จริง" ที่ดำเนินการในแต่ละครั้ง (ปิดด้วยset +x)
ShreevatsaR

10

ในเชลล์บางตัวรวมถึง bash 4.x ที่globstarเปิดใช้งานตัวเลือก**จะดำเนินการแบบเรียกซ้ำโดยทำไดเรกทอรีที่ตรงกัน เครื่องหมายดอกจันเพิ่มเติมไม่ได้แก้ไขการดำเนินการนี้


1
ขณะที่ผมกล่าวในคำตอบของฉัน แต่ระวังขัดต่อว่าksh93และzsh, bashไม่ symlinks การสำรวจในการเรียกซ้ำซึ่งโดยทั่วไปที่ไม่พึงประสงค์
Stéphane Chazelas

ตอนนี้ได้รับการแก้ไขในทุบตี 4.3
Stéphane Chazelas

1

หากคุณต้องการ "ดำน้ำลึก" ให้ใช้ตัวเลือก ls -R (เรียกซ้ำ) หรือใช้ find เช่น:

find . -ls

"find" จะดำดิ่งลงไปด้านล่างของแผนผังไดเรกทอรี (ตามที่ 'ls -R') และมีตัวเลือกอื่น ๆ อีกมากมายเช่นรายการไดเรกทอรี (-type d) ไฟล์เท่านั้น (-type f) หรือแสดงไฟล์ที่มีรายการอื่น ๆ คุณสมบัติ (ไม่มีผู้ใช้ใน / etc / passwd, การอนุญาตเฉพาะและอีกมากมาย) "find" นั้นค่อนข้างปลอดภัยกว่าในการเขียนสคริปต์ (เนื่องจากกฎการทำให้กลมระหว่างเชลล์ไม่สอดคล้องกันและการยกเว้นพิเศษสำหรับไฟล์ที่มีเครื่องหมายขีดกลาง ฯลฯ )

การใช้สัญลักษณ์แทนเชลล์ของเชลล์จะไม่สามารถใช้เพียงเครื่องหมายดอกจัน '*' บน dotfiles ในการแสดงรายการไฟล์ dotfiles เท่านั้นใช้:

ls .??*


-1

พิเศษ * ไม่เพิ่มระดับความลึก แต่ถ้าคุณลอง

 ls */*/*

- คุณจะได้รับรายการโฟลเดอร์ย่อยของโฟลเดอร์ย่อยในโฟลเดอร์ในโฟลเดอร์ปัจจุบัน ...


ไม่ถูกต้อง. ขึ้นอยู่กับเปลือกหอย*s พิเศษจะเพิ่มระดับความลึก
njsg

แล้วเปลือกหอยชนิดใดที่จะเพิ่มระดับความลึกของดาวพิเศษ?
VB9-UANIC

หลาย. การรวม GNU bashกับตัวเลือก globstar, korn shell และ zsh และอาจเป็นไปได้ว่าคนอื่นฉันเดา unix.stackexchange.com/a/62665/14831
njsg

-1

กริปหลักของฉันคือ echo ** / *. ext จะโดยทั่วไป ...

อาจหรืออาจไม่: รายการไฟล์. text ในไดเรกทอรีปัจจุบัน

อาจหรือไม่: รวมไฟล์. *. ext

โดยทั่วไปฉันต้องการให้นิพจน์ glob เป็น '** /' ซึ่งอาจส่งผลสตริงที่ไม่มีค่า (ไม่มีไดเรกทอรีย่อย) นี่คือวิธีที่ฉันแปลงนิพจน์ glob ในอินพุตโปรแกรม แน่นอนฉันรับประกันว่ามีความคิดเห็นอธิบายในตัวอย่างของการใช้งาน

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