ฉันรู้ว่าการใช้คำสั่งls
จะแสดงรายการไดเรกทอรีทั้งหมด แต่ls *
คำสั่งทำอะไร ฉันใช้มันและมันก็จะแสดงรายการไดเรกทอรี ดาวอยู่ข้างหน้าls
หมายความว่าจะสามารถแสดงรายการไดเรคทอรีได้ลึกแค่ไหน
ฉันรู้ว่าการใช้คำสั่งls
จะแสดงรายการไดเรกทอรีทั้งหมด แต่ls *
คำสั่งทำอะไร ฉันใช้มันและมันก็จะแสดงรายการไดเรกทอรี ดาวอยู่ข้างหน้าls
หมายความว่าจะสามารถแสดงรายการไดเรคทอรีได้ลึกแค่ไหน
คำตอบ:
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
**/*.c
a/b/c.c
a.c
a**.c
a.c
ab/c/d.c
zsh
**/.*
.* **/.*
***
**
*
**
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)
find -name *
อีกตัวอย่างที่ดีคือ find
โดยเฉพาะอย่างยิ่งที่มีรูปแบบที่ซับซ้อนมากขึ้นถ้ามีเป็นสิ่งหนึ่งในการแข่งขันในไดเรกทอรีปัจจุบันคนมักจะไม่ได้ตระหนักว่าพวกเขาไม่ได้ผ่านดอกจันไป
*.[ab]
ไม่ได้เป็นพิเศษในปลา .[ab]
[
คำสั่งls
เริ่มต้นที่ls .
: รายชื่อรายการทั้งหมดในไดเรกทอรีปัจจุบัน
คำสั่งls *
หมายถึง 'run ls ในการขยาย*
รูปแบบเชลล์'
รูปแบบการประมวลผลโดยเปลือกและขยายไปยังรายการทั้งหมดในไดเรกทอรีปัจจุบันยกเว้นผู้ที่เริ่มต้นด้วย*
.
มันจะลึกลงไปหนึ่งระดับ
การตีความของ*
รูปแบบสองหรือสามขึ้นอยู่กับเปลือกที่ใช้จริง
*
เป็นอักขระตัวแทนที่ตรงกับอักขระตั้งแต่ 0 ตัวขึ้นไป กระสุนสมัยใหม่บางตัวจะถูกย่อเก็บลงในไดเรกทอรีย่อยเมื่อเห็น**
รูปแบบ
*
จะเพิ่มบางอย่างพิเศษดูคำตอบอื่น ๆ อธิบาย globstar มันควรจะชัดเจนว่า ls ไม่เกี่ยวข้องกับเครื่องหมายดอกจันมันไม่เคยผ่านเครื่องหมายดอกจันเหล่านี้เลย เรียกใช้เพื่อดูสิ่งที่จะได้รับการดำเนินการเมื่อคุณเขียนecho ls *
ls *
คุณสามารถเข้าใจขั้นตอนทั้งหมดได้อย่างชัดเจนโดยพิมพ์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
ไดเรกทอรีสำหรับแต่ละผู้ใช้
bash
เป็นเปลือกของคุณ" ←และไม่ได้เปิดใช้งาน globstar shopt -s globstar
และลองอีกครั้ง ...
set -x
เริ่มพิมพ์คำสั่ง "จริง" ที่ดำเนินการในแต่ละครั้ง (ปิดด้วยset +x
)
ในเชลล์บางตัวรวมถึง bash 4.x ที่globstar
เปิดใช้งานตัวเลือก**
จะดำเนินการแบบเรียกซ้ำโดยทำไดเรกทอรีที่ตรงกัน เครื่องหมายดอกจันเพิ่มเติมไม่ได้แก้ไขการดำเนินการนี้
ksh93
และzsh
, bash
ไม่ symlinks การสำรวจในการเรียกซ้ำซึ่งโดยทั่วไปที่ไม่พึงประสงค์
หากคุณต้องการ "ดำน้ำลึก" ให้ใช้ตัวเลือก ls -R (เรียกซ้ำ) หรือใช้ find เช่น:
find . -ls
"find" จะดำดิ่งลงไปด้านล่างของแผนผังไดเรกทอรี (ตามที่ 'ls -R') และมีตัวเลือกอื่น ๆ อีกมากมายเช่นรายการไดเรกทอรี (-type d) ไฟล์เท่านั้น (-type f) หรือแสดงไฟล์ที่มีรายการอื่น ๆ คุณสมบัติ (ไม่มีผู้ใช้ใน / etc / passwd, การอนุญาตเฉพาะและอีกมากมาย) "find" นั้นค่อนข้างปลอดภัยกว่าในการเขียนสคริปต์ (เนื่องจากกฎการทำให้กลมระหว่างเชลล์ไม่สอดคล้องกันและการยกเว้นพิเศษสำหรับไฟล์ที่มีเครื่องหมายขีดกลาง ฯลฯ )
การใช้สัญลักษณ์แทนเชลล์ของเชลล์จะไม่สามารถใช้เพียงเครื่องหมายดอกจัน '*' บน dotfiles ในการแสดงรายการไฟล์ dotfiles เท่านั้นใช้:
ls .??*
พิเศษ * ไม่เพิ่มระดับความลึก แต่ถ้าคุณลอง
ls */*/*
- คุณจะได้รับรายการโฟลเดอร์ย่อยของโฟลเดอร์ย่อยในโฟลเดอร์ในโฟลเดอร์ปัจจุบัน ...
*
s พิเศษจะเพิ่มระดับความลึก
bash
กับตัวเลือก globstar, korn shell และ zsh และอาจเป็นไปได้ว่าคนอื่นฉันเดา unix.stackexchange.com/a/62665/14831
กริปหลักของฉันคือ echo ** / *. ext จะโดยทั่วไป ...
อาจหรืออาจไม่: รายการไฟล์. text ในไดเรกทอรีปัจจุบัน
อาจหรือไม่: รวมไฟล์. *. ext
โดยทั่วไปฉันต้องการให้นิพจน์ glob เป็น '** /' ซึ่งอาจส่งผลสตริงที่ไม่มีค่า (ไม่มีไดเรกทอรีย่อย) นี่คือวิธีที่ฉันแปลงนิพจน์ glob ในอินพุตโปรแกรม แน่นอนฉันรับประกันว่ามีความคิดเห็นอธิบายในตัวอย่างของการใช้งาน