ทำไม ls -d ยังแสดงรายการไฟล์และเอกสารอยู่ที่ไหน?


48
  • เมื่อระบุls --directory a*ว่าควรแสดงเฉพาะไดเรกทอรีที่ขึ้นต้นด้วยa*
  • แต่มันจะแสดงรายการไฟล์และไดเรกทอรีที่เริ่มต้นด้วย a

คำถาม :

  • ที่ฉันอาจพบเอกสารบางอย่างเกี่ยวกับเรื่องนี้อื่น ๆ กว่าmanและinfoที่ผมคิดว่าผมมองอย่างละเอียด?
  • ทำงานใน BASH เท่านั้นหรือไม่


5
echo a*จะแสดงรายการไฟล์ที่ขึ้นต้นด้วยa(ถ้ามี) ด้วย เพียงเพื่อให้ชัดเจนยิ่งขึ้นว่ามันไม่ได้lsทำสิ่งนี้ แต่เป็นการทุบตี
ash108

คำตอบ:


89

a*และ*a*ไวยากรณ์ดำเนินการโดยเปลือกที่ไม่ได้ตามlsคำสั่ง

เมื่อคุณพิมพ์

ls a*

ที่พรอมต์เปลือกของคุณเปลือกขยายไปยังรายการของแฟ้มที่มีอยู่ทั้งหมดในไดเรกทอรีปัจจุบันมีชื่อขึ้นต้นด้วยa* aยกตัวอย่างเช่นมันอาจขยายa*ลำดับและผ่านเหล่านั้นเป็นข้อโต้แย้งa1 a2 a3 คำสั่งตัวเองไม่เคยเห็นตัวละคร; เพียงเห็นอาร์กิวเมนต์ที่สาม, และlsls*a1a2a3

สำหรับวัตถุประสงค์ของการขยายสัญลักษณ์ "ไฟล์" หมายถึงเอนทิตีทั้งหมดในไดเรกทอรีปัจจุบัน ตัวอย่างเช่นa1อาจเป็นไฟล์ปกติa2อาจเป็นไดเรกทอรีและa3อาจเป็น symlink พวกเขาทั้งหมดมีรายการไดเรกทอรีและการขยายตัวแทนของเชลล์ไม่สนใจประเภทของรายการที่อ้างถึงเอนทิตี

แทบทุกเชลล์ที่คุณน่าจะใช้งานได้ (bash, sh, ksh, zsh, csh, tcsh, ... ) ใช้สัญลักษณ์แทน รายละเอียดอาจแตกต่างกัน แต่ไวยากรณ์พื้นฐานของการ*จับคู่ศูนย์หรือมากกว่าตัวอักษรและการ?จับคู่อักขระเดี่ยวใด ๆ มีความสอดคล้องกันอย่างสมเหตุสมผล

สำหรับ bash โดยเฉพาะจะมีการบันทึกไว้ในส่วน "การขยายชื่อไฟล์" ของคู่มือทุบตี เรียกใช้info bashและค้นหา "การขยายตัวของชื่อไฟล์" หรือดูที่นี่

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

ในทางกลับกันก็ยากที่จะเขียนคำสั่งเพื่อเปลี่ยนชื่อหลายไฟล์ ถ้าคุณเขียน:

mv *.log *.log.bak

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

find . -name '*.txt' -print

การขยาย wildcard ของเชลล์ขึ้นอยู่กับไวยากรณ์ของอาร์กิวเมนต์บรรทัดคำสั่งและชุดของไฟล์ที่มีอยู่ทั้งหมด มันไม่สามารถรับผลกระทบจากความหมายของคำสั่ง ตัวอย่างเช่นหากคุณต้องการย้าย.logไฟล์ทั้งหมดไปยังไดเรกทอรีหลักคุณสามารถพิมพ์:

mv *.log ..

หากคุณลืม..:

mv *.log

และมี.logไฟล์สองไฟล์ในไดเรกทอรีปัจจุบันซึ่งจะขยายเป็น:

mv one.log two.log

ซึ่งจะเปลี่ยนชื่อและข่มขี่one.logtwo.log

แก้ไข : และหลังจาก 52 upvotes, การยอมรับและตรา Guru บางทีฉันควรตอบคำถามในชื่อ

-dหรือ--directoryเลือกที่จะlsไม่บอกให้รายการไดเรกทอรีเท่านั้น มันบอกให้รายการไดเรกทอรีเช่นเดียวกับตัวเองไม่ใช่เนื้อหาของพวกเขา หากคุณให้ชื่อไดเรกทอรีเป็นอาร์กิวเมนต์lsโดยค่าเริ่มต้นมันจะแสดงรายการเนื้อหาของไดเรกทอรีเนื่องจากปกติแล้วเป็นสิ่งที่คุณสนใจ-dตัวเลือกจะบอกให้แสดงเฉพาะไดเรกทอรีเท่านั้น สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อรวมกับอักขระตัวแทน หากคุณพิมพ์:

ls -l a*

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

ls -ld a*

ซึ่งเทียบเท่ากับ:

ls -l -d a*

จำอีกครั้งว่าlsคำสั่งไม่เคยเห็น*ตัวละคร

สำหรับตำแหน่งที่จัดทำเอกสารนี้man lsจะแสดงเอกสารสำหรับlsคำสั่งเกี่ยวกับระบบ Unix ที่คล้ายกัน บนระบบที่ใช้ Linux ส่วนใหญ่lsคำสั่งเป็นส่วนหนึ่งของแพ็คเกจ GNU coreutils หากคุณมีinfoคำสั่งอย่างใดอย่างหนึ่งinfo lsหรือinfo coreutils lsควรให้เอกสารที่ชัดเจนและครอบคลุมมากขึ้น ระบบอื่น ๆ เช่น MacOS อาจใช้lsคำสั่งเวอร์ชันต่าง ๆและอาจไม่มีinfoคำสั่ง man lsสำหรับระบบที่ใช้ และls --helpจะแสดงข้อความการใช้งานที่ค่อนข้างสั้น (117 บรรทัดบนระบบของฉัน) หากคุณกำลังใช้การใช้งาน coreutils ของ GNU

และแม้กระทั่งผู้เชี่ยวชาญก็จำเป็นต้องอ่านเอกสารนี้แล้ว ดูมุกตลกคลาสสิกนี้ด้วย


8
@Thomas: a*ขยายไปยังรายชื่อของไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันaมีชื่อขึ้นต้นด้วย
Keith Thompson

2
@Thomas: หรือในสิ่งที่คุณระบุไดเรกทอรี:ls subdir/a*
Keith Thompson

1
จริงๆเห็นคำสั่งดำเนินการหลังจากการขยายตัวของเปลือกechoมัน ดังนั้นหากคุณต้องการที่จะรู้ว่าสิ่งที่เกิดขึ้นเมื่อคุณทำls a*ครั้งแรกรันecho ls a*
Carlos Campderrós

1
หรือเพียงแค่echo a*... เปลือกหอยจะขยายตัวออกไป
ไร้ประโยชน์

2
@sendmoreinfo: ขึ้นอยู่กับเชลล์และการตั้งค่า ใน csh และ tcsh การขยาย glob ที่ล้มเหลวเป็นข้อผิดพลาด ในทุบตีshopt -s failglobทำให้เกิดพฤติกรรมเดียวกัน การตั้งค่าnullglobแต่ไม่ใช่failglobสาเหตุตัวอย่างเช่น*nosuchfile*การขยายเป็นสตริงว่าง
Keith Thompson

27

ดูคำตอบของ Keith Thompson; แต่เพื่ออธิบายสาเหตุที่ls --directory a*แสดงไฟล์และไดเรกทอรี: --directoryตัวเลือกไม่ได้ระงับไฟล์ที่ไม่ใช่ไดเรกทอรี แต่จะแสดงรายการไดเรกทอรีเป็นเช่นนั้นในขณะที่รายการอื่นจะแสดงเนื้อหา ตัวอย่าง:

$ mkdir foo
$ touch foo/bar
$ ls foo
bar
$ ls --directory foo
foo

3
ตัวอย่างนั้นน่าสนใจยิ่งกว่าด้วย-Fตัวเลือก
glenn jackman

6

จะชัดเจนมากมันมีเอกสารในหน้าคู่มือ ls (1) :

-d, - ไดเรกทอรีรายการไดเรกทอรีรายการแทนเนื้อหาและไม่ยกเลิกการเชื่อมโยงสัญลักษณ์สัญลักษณ์

เพื่อความเป็นธรรม "รายการแทนเนื้อหา" อาจเป็นคำอธิบายที่มากขึ้น:

หาก FILE เป็นไดเรกทอรีให้แสดงรายการไดเรกทอรีแทนการแสดงรายการเนื้อหาของไดเรกทอรีนั้น หาก FILE เป็นลิงก์สัญลักษณ์ให้แสดงรายการลิงก์แทนไฟล์ที่ชี้ไปที่ลิงก์


จะเป็นเรื่องอื้อฉาวในขณะที่ตัวเลือก -d อาจอธิบายได้ (ถ้าใช้บ่อย) ในหน้า man การขยายตัวของอาร์กิวเมนต์และ wildcard ไม่ได้จัดทำเป็นเอกสารไว้ในหน้า man ls เพราะเชลล์ทำเสร็จแล้ว หากคุณปิดการขยายชื่อไฟล์ในเชลล์ของคุณ "ls a *" จะแสดงเฉพาะไฟล์ที่ชื่อ 'a *' เท่านั้น
Johnny

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

4

globbing

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

ใน Unix ต้นglobถูกนำมาใช้จริงโดยโปรแกรมแยกเรียกว่า/etc/glob(ดูหน้า 10 ของคู่มือ UNIX เก่านี้สำหรับเอกสารประกอบสำหรับการที่) ทุกวันนี้มันเป็นกิจวัตรประจำวันของโค้ดที่จัดทำโดยไลบรารีโค้ดและเป็นที่นิยมใช้โดยเชลล์ แหล่งที่มา : วิกิพีเดีย

ไดเรกทอรี

เหตุใดจึงls -dแสดงรายการไฟล์รวมทั้งไดเรกทอรี ...

lsหน้าคนอธิบายว่าทำไมเกิดเหตุการณ์นี้ แต่มีคำอธิบายสั้นมาก ดังนั้นนี่คือความพยายามในการอธิบายเพิ่มเติม:

โดยค่าเริ่มต้นlsรายการเนื้อหาของไดเรกทอรีเมื่อได้รับชื่อของพวกเขาและจะทำสิ่งเดียวกันสำหรับsymlinkไปยังไดเรกทอรี -dตัวเลือกหมายความว่า"เมื่อได้รับชื่อ (s) ของไดเรกทอรี (IES)" (ซึ่งยังสามารถได้รับโดยปริยายโดยglobBing)เพียงแสดง _name_s ของไดเรกทอรี (IES) แต่ไม่ได้เนื้อหาของพวกเขา ในทำนองเดียวกันเมื่อระบุชื่อ symlink ไปยังไดเรกทอรี (อย่างชัดเจนหรือโดยปริยาย ) ให้แสดงชื่อไฟล์ของ symlink ไม่ใช่เนื้อหาของไดเรกทอรีที่อ้างอิง

-dตัวเลือกมีอะไรจะทำเท่าที่ผมสามารถบอกได้ด้วยซึ่งรายการที่มีการระบุไว้; นี้สามารถทำได้ (ที่มา: ที่นี่ ) ด้วยเช่นดังนั้น:find find . -maxdepth 1 -type dผมไม่แน่ใจว่าถ้ามีเป็นวิธีที่ดีที่จะทำเฉพาะกับ lsGNU นี่คือตัวอย่างของวิธีใช้findคำสั่ง

ดังนั้นเพื่อสรุป: โดยค่าเริ่มต้นlsจะแสดงเนื้อหาของไดเรกทอรีเมื่อกำหนดชื่อพา ธ -dเปลี่ยนพฤติกรรมนี้แสดงเฉพาะชื่อไดเรกทอรีเท่านั้นเช่นเดียวกับที่ทำกับไฟล์มาตรฐาน


3

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

> {ice} ~ :10:47 % ls -l / 
total 97
drwxr-xr-x   2 root root  4096 May  3 00:27 bin
drwxr-xr-x   4 root root  1024 May  3 14:17 boot
drwxr-xr-x   2 root root  4096 Apr 29 13:44 cdrom
drwxr-xr-x  18 root root  4420 May  9 09:58 dev
...
lrwxrwxrwx   1 root root    33 May  3 14:16 vmlinuz -> boot/vmlinuz-3.9.0-030900-generic
lrwxrwxrwx   1 root root    29 May  3 11:07 vmlinuz.old -> boot/vmlinuz-3.8.0-19-generic
> {ice} ~ :10:47 % ls -ld /
drwxr-xr-x 25 root root 4096 May  3 14:16 /

2

เอกสารเป็นส่วนหนึ่งของเปลือก โดยเฉพาะอย่างยิ่งเชลล์ดำเนินการขยายและทดแทนในลำดับที่เฉพาะเจาะจงก่อนที่จะดำเนินการคำสั่ง

ลำดับของการขยายคำสำหรับเชลล์ที่เข้ากันได้ของ Bourneคือ

  1. Tilde Expansion
  2. การขยายพารามิเตอร์
  3. การทดแทนคำสั่ง
  4. การขยายเลขคณิต
  5. การแยกฟิลด์
  6. การขยายชื่อพา ธ
  7. การลบคำพูด

ดังนั้นlsคำสั่งจะไม่เห็น*ตัวละครอาร์กิวเมนต์ถูกขยายออกไปพร้อมกับไฟล์ทั้งหมดที่ตรงกับa*รูปแบบ glob สิ่งนี้แตกต่างจาก Windows โดยที่แต่ละคำสั่งที่ต้องการชื่อไฟล์นั้นจะต้องใช้คุณสมบัตินี้


1

คำสำคัญที่คุณต้องการ ( man bash) คือ "การขยายชื่อพา ธ "


3
เพิ่มเติมเช่น "การขยายชื่อเส้นทาง" หรือ "การสร้างชื่อไฟล์" เกี่ยวข้องกับ "การจับคู่รูปแบบ" แต่ไม่เหมือนกัน
Stéphane Chazelas

@StephaneChazelas แน่นอน แต่ "การจับคู่รูปแบบ" เป็นส่วนย่อยของ "การขยายชื่อพา ธ " ในหน้าคนในขณะที่ "การสร้างชื่อไฟล์" ไม่ได้เกิดขึ้นที่นั่นเลย (แค่ในเอกสารข้อมูล)
Hauke ​​Laging
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.