วิธีการรวมคำสั่ง mv หลังจากค้นหาคำสั่ง?


61

ฉันกำลังค้นหาไฟล์ที่ชื่อซึ่งมีAAAอยู่ในเส้นทางของพวกเขาโดยใช้คำสั่งต่อไปนี้:

find path_A -name "*AAA*"

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

คำตอบ:


87

ด้วย GNU mv :

find path_A -name '*AAA*' -exec mv -t path_B {} +

ที่จะใช้-execตัวเลือกการค้นหาซึ่งแทนที่{}ด้วยแต่ละผลการค้นหาในทางกลับกันและเรียกใช้คำสั่งที่คุณให้มัน ตามที่อธิบายไว้ในman find:

   -exec command ;
          Execute  command;  true  if 0 status is returned.  All following
          arguments to find are taken to be arguments to the command until
          an  argument  consisting of `;' is encountered.  

ในกรณีนี้เรากำลังใช้+เวอร์ชัน-execเพื่อให้เราสามารถดำเนินการได้น้อยmvที่สุด:

   -exec command {} +
          This  variant  of the -exec action runs the specified command on
          the selected files, but the command line is built  by  appending
          each  selected file name at the end; the total number of invoca‐
          tions of the command will  be  much  less  than  the  number  of
          matched  files.   The command line is built in much the same way
          that xargs builds its command lines.  Only one instance of  `{}'
          is  allowed  within the command.  The command is executed in the
          starting directory.

อย่าลืม "\;" ในตอนท้ายของ exec!
ชาร์ลส์โรท

@Charles โรท: มัน+ซึ่ง dows งานที่คุณสามารถอ่านคำพูดของฉันข้างต้นหรือman findแทน
cuonglm

ขอบคุณสำหรับสิ่งนี้! ฉันพยายามใช้-exec mv {} path_b +และมันล้มเหลวด้วยข้อผิดพลาดของการอนุญาต TBH ฉันยังไม่เข้าใจว่าทำไม แต่-exec mv -t path_b {} +ทำงานได้ดี!
Jeremy Davis

6
@JeremyDavis เมื่อใช้-exec ... {} +ที่จะต้องมีสิ่งสุดท้ายก่อน{} +นี่คือเหตุผลที่เขาใช้และไม่ได้mv -t destdir {} + mv {} destdir +หวัดหนึ่งใช้-exec mv {} destdir ';'แทน แต่จะมีการดำเนินการmvหนึ่งครั้งสำหรับแต่ละไฟล์
Kusalananda

23

คุณสามารถทำสิ่งที่ชอบด้านล่างเช่นกัน

find path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B

ที่ไหน

  1. -0หากมีช่องว่างหรือตัวอักษร (รวมถึงการขึ้นบรรทัดใหม่) คำสั่งจำนวนมากจะไม่ทำงาน ตัวเลือกนี้จะใส่ใจกับชื่อไฟล์ที่มีพื้นที่ว่าง
  2. -Iแทนที่การเกิดขึ้นของ replace-str ในอาร์กิวเมนต์เริ่มต้นด้วยชื่อที่อ่านจากอินพุตมาตรฐาน นอกจากนี้ช่องว่างที่ไม่มีเครื่องหมายอัญประกาศจะไม่ยุติรายการอินพุต ตัวคั่นเป็นอักขระขึ้นบรรทัดใหม่แทน

การทดสอบ

ฉันสร้างสองไดเรกทอรีเป็นและsourcedir destdirตอนนี้ผมสร้างพวงของไฟล์ภายในsourcedirเป็นfile1.bak, file2.bakและfile3 with spaces.bak

ตอนนี้ฉันดำเนินการคำสั่งเป็น

find . -name "*.bak" -print0 | xargs -0 -I {} mv {} /destdir/

ตอนนี้ภายในdestdirเมื่อฉันทำlsฉันจะได้เห็นว่าไฟล์ที่ได้ย้ายจากการsourcedirdestdir

อ้างอิง

http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/


22

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

find path_A -maxdepth 1 -name "*AAA*" -exec mv {} path_B \;

หากคุณต้องการค้นหาไฟล์ทั้งหมดซ้ำในpath_A:

find path_A -name "*AAA*" -exec mv {} path_B \;

นี่ไม่ใช่ไวยากรณ์เฉพาะของ OS X แต่เป็นแบบเดียวกันกับที่findฉันเคยใช้ จุดที่ดี: -maxdepth(โดยทั่วไปถ้า path_B เป็นไดเรกทอรีย่อย - หลีกเลี่ยงmvการย้ายไฟล์ไปที่นั่นแล้ว!) และการใช้ \; (ดังนั้น {} ไม่จำเป็นต้องเป็นพารามิเตอร์สุดท้ายและmvสามารถใช้ไวยากรณ์ปกติได้)
drevicko

6

-execเป็นวิธีที่ดีที่สุดที่จะทำเช่นนี้ หากด้วยเหตุผลใดก็ตามนี่ไม่ใช่ตัวเลือกคุณสามารถอ่านผลลัพธ์ในลูปได้ด้วย:

find path_A -name "*AAA*" -print0 | 
    while IFS= read -r -d $'\0' file; do mv "$file" path_B; done

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

mv $(find path_A -name "*AAA*") path_B

แต่ใช้ขณะที่ลูป


วิธีที่ง่ายกว่านั้นยังคงล้มเหลวหากyour file names consist only of simple alphanumeric charactersเช่นหากใช้งานARG_MAX


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