ทำความเข้าใจกับตัวเลือก -exec (1) (เครื่องหมายปีกกาและเครื่องหมายบวก)


17

ใช้คำสั่งต่อไปนี้ใครช่วยอธิบายหน่อยได้ไหมว่าอะไรคือจุดประสงค์สำหรับการจัดฟันส่วนปลาย ({}) และเครื่องหมายบวก (+)?

และคำสั่งจะทำงานแตกต่างกันอย่างไรหากถูกแยกออกจากคำสั่ง

find . -type d -exec chmod 775 {} +

คำตอบ:


19

วงเล็บปีกกาจะถูกแทนที่ด้วยผลลัพธ์ของfindคำสั่งและchmodจะถูกรันบนแต่ละอัน +ทำให้findพยายามที่จะทำงานตามคำสั่งน้อยที่สุด (ดังนั้นchmod 775 file1 file2 file3เมื่อเทียบกับchmod 755 file1 , chmod 755 file2, chmod 755 file3) หากไม่มีคำสั่งก็จะทำให้เกิดข้อผิดพลาด นี่คือทั้งหมดที่อธิบายในman find:

-exec command ;

      ดำเนินการคำสั่ง ; เป็นจริงถ้าส่งคืนสถานะ 0 อาร์กิวเมนต์ทั้งหมดต่อไปนี้ที่จะfindถูกนำไปเป็นอาร์กิวเมนต์ของคำสั่งจนกว่าอาร์กิวเมนต์ประกอบด้วย '; ' สตริง ' {}' จะถูกแทนที่ด้วยชื่อไฟล์ปัจจุบันกำลังดำเนินการทุกที่มันเกิดขึ้นในการขัดแย้งกับคำสั่งที่ไม่เพียง findแต่ในการขัดแย้งที่มันเป็นคนเดียวในขณะที่บางรุ่น ...

-exec command {} +

      การ-execกระทำที่แตกต่างนี้รันคำสั่งที่ระบุในไฟล์ที่เลือก แต่บรรทัดคำสั่งจะถูกสร้างโดยการต่อท้ายชื่อไฟล์ที่เลือกแต่ละชื่อที่ท้าย จำนวนการเรียกใช้คำสั่งทั้งหมดจะน้อยกว่าจำนวนไฟล์ที่ตรงกัน ...


12

นอกจากคำตอบของ terdon แล้ว

  • “ ชัดเจน” -exec …ต้องถูกยกเลิกด้วยเครื่องหมายอัฒภาค ( ;) หรือเครื่องหมายบวก ( +) เซมิโคลอนเป็นอักขระพิเศษในเชลล์ (หรืออย่างน้อยทุกเชลล์ที่ฉันเคยใช้) ดังนั้นถ้าจะใช้เป็นส่วนหนึ่งของfindคำสั่งมันจะต้องหลบหนีหรืออ้างถึง ( \;,";"หรือ';')
  • ด้วย-exec … ;การ{}สตริงอาจปรากฏจำนวนครั้งใด ๆ ในคำสั่งให้รวมศูนย์หรือสองคนหรือมากกว่าในตำแหน่งใด ๆ  ดูนี้ สำหรับตัวอย่างของทำไมคุณอาจต้องการที่จะทำโดยไม่ต้องใช้-exec {}  มีสองคนหรือมากกว่าที่ปรากฏจะเป็นประโยชน์อย่างยิ่งเพราะใน (อย่างน้อย) บางรุ่นfindที่{}ไม่จำเป็นต้องเป็นคำด้วยตัวเอง; มันสามารถมีตัวละครอื่น ๆ ที่จุดเริ่มต้นหรือจุดสิ้นสุด; เช่น,

    find . -type f -exec mv {} {}.bak ";"
    

    ด้วย-exec … +การ{}สตริงจะต้อง+ปรากฏเป็นอาร์กิวเมนต์สุดท้ายก่อน คำสั่งเช่น

    find . -name "*.bak" -exec mv {} backup_folder +
    

    ผลลัพธ์ในfind: missing argument to ‘-exec’ข้อความแสดงข้อผิดพลาดปริศนา

    • วิธีหลีกเลี่ยงปัญหาสำหรับสิ่งนี้เฉพาะสำหรับคำสั่งcpและmv

      find . -name "*.bak" -exec mv -t backup_folder {} +
      

      หรือ

      find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
      

    {}จะต้องเป็นคำด้วยตัวเอง; มันไม่สามารถมีตัวละครอื่น ๆ ที่จุดเริ่มต้นหรือจุดสิ้นสุด และใน (อย่างน้อย) บางเวอร์ชั่นfindคุณอาจมีมากกว่าหนึ่ง{}รุ่น

  • หมายเหตุด้านสุขภาพ: คุณสามารถพูดได้

    หา -name "* .sh" -type f -executable -exec {} ตัวเลือก args ที่นี่ ";"

    เพื่อเรียกใช้สคริปต์แต่ละตัวของคุณ แต่

    หา -name "* .sh" -type f -executable -exec {} +

    รันหนึ่งในสคริปต์ของคุณด้วยชื่อของคนอื่น ๆ ทั้งหมดเป็นพารามิเตอร์ มันคล้ายกับว่า

    ./*.sh
    

    เป็นคำสั่งของเชลล์ยกเว้นfindไม่ได้รับประกันว่ามันจะเรียงลำดับผลการค้นหาของคุณจึงไม่รับประกันของการทำงานaaa.sh (ตามลำดับตัวอักษรแรกของคุณ*.shไฟล์) ./*.shที่คุณจะเป็นกับการทำงาน

  • แง่มุมfindที่อาจไม่ชัดเจนสำหรับผู้เริ่มต้นคือบรรทัดคำสั่งคือคำสั่งที่ใช้งานได้ในภาษาอาร์เคน ตัวอย่างเช่น,

    find . -name "*.sh" -type f -executable -print
    

    วิธี

    for each file
        if the file’s name matches `*.sh` (i.e., if it ends with `.sh`)
        then
            if it is a plain file (i.e., not a directory)
            then
                if it is executable (i.e., the appropriate `---x--x--x` bit is set)
                then
                    print the file’s name
                end if
            end if
        end if
    end loop
    

    หรือเพียงแค่

    for each file
        if the file’s name matches `*.sh`  AND  it is a plain file  AND  it is executable
        then
            print the file’s name
        end if
    end loop
    

    -คำหลักบางคำเป็นทั้งการกระทำที่ปฏิบัติการได้และการทดสอบ โดยเฉพาะอย่างยิ่งนี่เป็นเรื่องจริงสำหรับ-exec … ;; ตัวอย่างเช่น,

    find . -type f -exec grep -q cat {} ";" -print
    

    แปลเป็น

    สำหรับแต่ละไฟล์
        ถ้ามันเป็นไฟล์ธรรมดา (เช่นไม่ใช่ไดเรกทอรี)
        แล้วก็
            ดำเนินการ grep -q cat ชื่อไฟล์
            หากกระบวนการประสบความสำเร็จ (เช่นออกจากสถานะ 0)
            แล้วก็
                พิมพ์ชื่อไฟล์
            จบถ้า
        จบถ้า
    ปลายวน

    ซึ่งจะพิมพ์ชื่อของไฟล์ทั้งหมดที่มีสตริง“ cat” และในขณะที่นี่คือสิ่งที่grepสามารถทำได้ด้วยตัวเอง (กับตัวเลือก (ตัว-lพิมพ์เล็กL)) มันจะมีประโยชน์ที่จะใช้มันfindเพื่อค้นหาไฟล์ที่มีสตริงที่แน่นอนและมีขนาดที่แน่นอนและเป็นเจ้าของโดยเจ้าของบางราย และถูกแก้ไขในช่วงเวลาหนึ่ง….

    -exec … +แต่นี้ไม่ได้ทำงานให้ เนื่องจาก-exec … +เรียกใช้งานคำสั่งเดียวสำหรับไฟล์หลาย ๆ ไฟล์มันไม่สมเหตุสมผลเลยที่จะใช้มันเป็นเงื่อนไขตรรกะภายในfor each file …ลูป

  • ด้านพลิกของด้านบนคือfindโดยทั่วไปแล้วจะออกด้วยสถานะการออกเป็น 0 เว้นแต่คุณจะให้อาร์กิวเมนต์ที่ไม่ถูกต้องหรือพบกับไดเรกทอรีที่ไม่สามารถอ่านได้ แม้ว่าโปรแกรมที่คุณดำเนินการจะล้มเหลว (ออกจากสถานะออกที่ไม่เป็นศูนย์), findจะออกโดยมีสถานะออกเป็น 0  ยกเว้น  ว่าโปรแกรมที่คุณดำเนินการ-exec … +ล้มเหลว (ออกด้วยสถานะออกไม่เป็นศูนย์) findจะออกจาก ด้วยสถานะการออกที่ไม่เป็นศูนย์

นอกเหนือจากหนึ่งล้านเวอร์ชันfind(1) และทดสอบสิ่งที่findเกิดขึ้นจริงกับสองระบบแล้ว ข้อมูลจำเพาะของ Open Group Base Issue 7, 2013 Edition ยัง ให้ข้อมูลบางอย่างเกี่ยวกับสิ่งที่findต้องทำอาจและต้องไม่ทำ


3
ระวังว่าตัวอย่างที่คุณใช้... -exec mv {} {}.bak ...นั้นไม่ได้รับประกันว่าจะทำงานได้อย่างที่คาดไว้กับfindการใช้งานทั้งหมด สถานะมาตรฐาน POSIX {}จะต้องปรากฏขึ้นตามลำพังเพื่อให้ได้รับการยอมรับเสมอมิฉะนั้นลักษณะการทำงานมีอิสระที่จะไม่เปลี่ยนแปลงอักขระหรือแทนที่ด้วยชื่อพา ธ ในกรณีที่อดีตคำสั่งทั้งหมดของคุณเป็นหลักจะลบไฟล์ทั้งหมด แต่คนสุดท้ายพบ ...
jlliagre
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.