เหตุใดจึงพบพิมพ์ './' นำหน้าหากไม่มีเส้นทางให้


13

ทำไมมันจึงfindพิมพ์ออกมานำ./ไปสู่ผลลัพธ์หากไม่มีการกำหนดเส้นทาง

$ find
./file1
./file2
./file3

อะไรคือสาเหตุที่ไม่พิมพ์ออกมา?

$ find
file1
file2
file3

คำตอบ:


16

เหตุผลว่าทำไมคุณเห็นนี้เป็นเพราะการพัฒนาของ GNU เลือกเพื่อให้พฤติกรรมที่ "เหมาะสม" สำหรับเมื่อไม่มีเส้นทางที่จะได้รับ ในทางตรงกันข้ามPOSIXไม่ได้ระบุว่าพารามิเตอร์เป็นตัวเลือก:find find

findยูทิลิตี้จะซ้ำลงไดเรกทอรีลำดับชั้นจากแต่ละไฟล์ระบุโดยเส้นทาง , การประเมินนิพจน์บูลีนประกอบด้วยพรรคอธิบายไว้ในส่วนถูกดำเนินการสำหรับแต่ละไฟล์พบ แต่ละตัวถูกดำเนินการเส้นทางจะถูกประเมินไม่เปลี่ยนแปลงตามที่มันถูกจัดเตรียมไว้รวมถึง<slash>อักขระต่อท้ายทั้งหมด ชื่อพา ธ ทั้งหมดสำหรับไฟล์อื่น ๆ ที่พบในลำดับชั้นจะประกอบด้วยการรวมกันของตัวถูกดำเนินการเส้นทางปัจจุบัน a <slash>หากตัวถูกดำเนินการเส้นทางปัจจุบันไม่ได้จบในหนึ่งและชื่อไฟล์ที่เกี่ยวข้องกับเส้นทางตัวถูกดำเนินการ ส่วนที่สัมพันธ์กันจะต้องไม่มีส่วนประกอบของจุดหรือจุดใดจุดหนึ่งไม่มีส่วนท้ายอักขระและ<slash>อักขระเดียวเท่านั้นระหว่างส่วนประกอบชื่อพา ธ

คุณสามารถเห็นความแตกต่างในบทสรุปสำหรับแต่ละคน GNU มีรายการเสริม (เช่นเดียวกับการประชุม) ในวงเล็บเหลี่ยม:

find [-H] [-L] [-P] [-D debugopts] [-Olevel] [starting-point...]
       [expression]

ในขณะที่ POSIX ไม่ได้ระบุว่าสามารถเลือกได้:

find [-H|-L] path... [operand_expression...]

ในโปรแกรม GNU ทำในftsfind.c:

  ถ้า (ว่างเปล่า)
    {
      / *
       * เราใช้ตัวแปรชั่วคราวที่นี่เพราะการกระทำบางอย่างแก้ไข
       * เส้นทางชั่วคราว ดังนั้นถ้าเราใช้ค่าคงที่สตริง
       * เราได้รับ coredump ตัวอย่างที่ดีที่สุดคือถ้าเราพูด
       * "find -printf% H" (หมายเหตุไม่ใช่ "find. -printf% H")
       * /
      char defaultpath [2] = ".";
      return find (defaultpath);
    }

และตัวอักษร"."ถูกใช้เพื่อความเรียบง่าย ดังนั้นคุณจะเห็นผลลัพธ์เดียวกันกับ

find

และ

find .

เพราะ (และ POSIX ตกลง) เส้นทางที่กำหนดจะถูกใช้เพื่อนำหน้าผลลัพธ์ (ดูด้านบนสำหรับการต่อข้อมูล )

ด้วยการทำงานเพียงเล็กน้อยเราสามารถกำหนดได้ว่าเมื่อใดที่มีการเพิ่มสถานที่นั้น มันมีอยู่ในการสร้างครั้งแรกของ "findutils" ในปี 1996 (ดูfind.c):

+  /* If no paths are given, default to ".".  */
+  for (i = 1; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
+    process_top_path (argv[i]);
+  if (i == 1)
+    process_top_path (".");
+
+  exit (exit_status);
+}

จากรายการเปลี่ยนแปลงสำหรับการค้นหา 3.8 ดูเหมือนว่าจะเป็นเช่นนี้

Sat Dec 15 19:01:12 1990  David J. MacKenzie  (djm at egypt)

        * find.c (main), util.c (usage): Make directory args optional,
        defaulting to "."

11

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

เป็นตัวอย่างให้พิจารณาไดเร็กทอรีที่มีไฟล์เหล่านี้:

$ ls
--link  --no-clobber

ตอนนี้ลองนึกภาพว่าคำสั่งนี้จะทำงานอย่างไรหากชื่อไฟล์ถูกจัดเตรียมไว้โดยไม่มี./ด้านหน้า:

$ find -type f -exec cp -t ../ {} +

เราสามารถอธิบายปัญหาด้วยfindตัวเอง ลองเรียกใช้ในไดเรกทอรีเดียวกันกับข้างบน ผลงานดังต่อไปนี้:

$ find ./*
./--link
./--no-clobber

ล้มเหลวต่อไปนี้:

$ find *
find: unknown predicate `--link'
Try 'find --help' for more information.

1
มันสมเหตุสมผลแล้ว แต่มีคำถามว่าทำไมมันไม่ได้เติม '.' ไว้ล่วงหน้า find *เมื่อคุณเรียกใช้
nr

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

3
บางรุ่นfile ต้องการให้ผู้ใช้ระบุพา ธ (เช่น BSD find บน OS X) find . -type f ...ดังนั้นคุณจะต้องชัดเจนพูดอะไรบางอย่างเช่น จากตรงนั้นมันไม่ใช่ขั้นตอนที่ยิ่งใหญ่สำหรับการค้นหาบางรุ่น (เช่น GNU find) เพื่อเริ่มต้น.และปล่อยให้ทุกอย่างเป็นไป
ilkkachu

1
เหตุผลที่find *ไม่ได้แสดงให้เห็น.เป็นเพราะ*รายชื่อไฟล์และโฟลเดอร์ทั้งหมด .แต่ไม่รวม ทำecho *ในไดเรกทอรีที่มีเพียงหนึ่งหรือสองไฟล์และคุณจะเห็นว่า .ไม่มีในรายการ ดังนั้นfind *ดำเนินการกับแต่ละไฟล์ที่ขยาย มันเหมือนกับว่าคุณพูดfind Desktop/จากไดเรกทอรีบ้าน คุณจะเห็นผลลัพธ์เป็นDesktop/foo_bar.txt
Sergiy Kolodyazhnyy

1
@ John1024: ฉันเชื่อว่าMrigeshและThomas Dickeyตอบคำถามได้ถูกต้องแล้ว คำตอบนี้ระบุว่าทำไมจึงสะดวกที่findจะทำเช่นนั้น คุณมีข้อมูลอ้างอิงที่เชื่อถือได้เพื่อสนับสนุนการอ้างสิทธิ์โดยนัยที่findออกแบบมาเพื่อทำงานในลักษณะนี้ด้วยเหตุผลนี้หรือไม่?
G-Man กล่าวว่า 'Reinstate Monica'

4

findคำสั่งต้องการเส้นทาง (s) เพื่อค้นหา หากเราไม่ได้ระบุไว้มันจะใช้ไดเรกทอรีปัจจุบัน ( .) เป็นจุดเริ่มต้น ในทำนองเดียวกันหากคุณผ่านเส้นทางเช่น/tmpจะถือว่าเป็นจุดเริ่มต้น และผลลัพธ์ก็คือ

หากไดเรกทอรีปัจจุบัน:

        $ find
or
        $ find .

output:
        ./file1
        ./file2
        ./file3

หาก/tmpไดเรกทอรี:

        $ find /tmp

output:
        /tmp/file4
        /tmp/file5

หากabcไดเรกทอรีภายใต้ไดเรกทอรีปัจจุบัน:

        $ find abc

output:
        abc/file6
        abc/file7

หากหลายไดเรกทอรีภายใต้ไดเรกทอรีปัจจุบัน:

        $ find fu bar

output:
        fu/file10
        fu/file11
        bar/file8
        bar/file9

ใช่ฉันเห็นด้วยfindต้องใช้พา ธ เพื่อค้นหาอะไรก็ได้และมันจะเป็นค่าเริ่มต้นไปยังไดเรกทอรีปัจจุบัน คำถามคือทำไมมันพิมพ์ออกชั้นนำ./เมื่อเป็นเพียงเช่นเดียวกับfile.txt ./file.txt
nr

1
มันไม่ใช่สิ่งที่พบเพิ่ม "." ในตอนเริ่มต้นมันจะเพิ่มสิ่งที่คุณให้เป็นเส้นทางไม่ว่าจะเป็น "/ tmp" "abc" หรือ " มันจะคืนค่าทั้งหมดตามลำดับ
Mrigesh Priyadarshi

-2

หากคุณไม่ได้ระบุพา ธfindคำสั่งจะถือว่า${PWD}พา ธ นั้นและพิมพ์ออกมาบนเอาต์พุต ผู้ใช้ที่ไม่ระบุเส้นทางจะไม่เปลี่ยนวิธีการfindทำงาน และค้นหาทำงานได้เสมอกับเส้นทางตามค่าเริ่มต้น


1
ฉันเห็น. แต่ถ้าคุณดำเนินการได้ภายใต้การ/tmpแล้ว$PWDคือไม่ได้/tmp ./
nr

หากคุณต้องการเห็นการ preceeding /tmpให้รันคำสั่งfind /tmpหากคุณไม่ได้ระบุพา ธ มันจะเป็นไดเรกทอรีปัจจุบันเสมอซึ่งก็คือ./
MelBurslan

1
/tmpมันไม่ใช่ว่าผมอยากจะเห็นเทมเพลตก่อนหน้า $PWDมันเป็นเรื่องที่เป็นไปไม่ได้
nr

คำขอโทษของฉัน${PWD}คือการใช้คำฟุ่มเฟือยที่ไม่ถูกต้อง
MelBurslan

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