วิธีการคัดลอกไดเรกทอรีซ้ำโดยใช้ลิงก์สำหรับแต่ละไฟล์


52

ฉันต้องการสร้าง "คัดลอก" ของทรีไดเรกทอรีซึ่งแต่ละไฟล์เป็นฮาร์ดลิงก์ไปยังไฟล์ต้นฉบับ

ตัวอย่าง: ฉันมีโครงสร้างไดเรกทอรี:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

นี่คือผลที่คาดหวัง "สำเนา" ของแผนผังไดเรกทอรีที่แต่ละไฟล์เป็นฮาร์ดลิงก์ไปยังไฟล์ต้นฉบับ:

dirB/            #  normal directory
dirB/file1       #  hardlink to dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  hardlink to dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  hardlink to dirA/y/file3

คำตอบ:


50

บน Linux (แม่นยำยิ่งขึ้นกับ GNU และbusyboxการใช้งานcpตามที่พบในระบบที่มี Linux เป็นเคอร์เนล) และ FreeBSD ล่าสุดนี่คือวิธี:

cp -al dirA dirB

สำหรับโซลูชันแบบพกพาที่มากขึ้นดูคำตอบโดยใช้ pax และ cpio โดยStéphane Chazelas


โปรดทราบว่าเช่นเดียวpaxกับ FreeBSD cp -aไม่ได้เชื่อมโยงไปยังฮาร์ดลิงก์
Stéphane Chazelas

ระวังว่าฮาร์ดลิงก์ไม่ทำงานข้ามการเมานต์ระบบไฟล์แยกกัน
เดฟ

24

POSIXly คุณจะใช้paxในโหมดอ่าน + เขียนพร้อม-lตัวเลือก:

pax -rwlpe -s /A/B/ dirA .

( -peเก็บรักษาคุณลักษณะทั้งหมดเป็นไปได้ของไฟล์ (ในกรณีนี้ไดเรกทอรีเท่านั้น) ที่มีการคัดลอกเช่น GNU cp's -aไม่)

ตอนนี้แม้ว่ามาตรฐานคำสั่งที่ไม่จำเป็นต้องมากแบบพกพา

เริ่มแรกระบบที่ใช้ GNU / Linux หลายระบบไม่ได้รวมอยู่ในpaxค่าเริ่มต้น (แม้ว่าจะเป็นโปรแกรมอรรถประโยชน์ POSIX ที่ไม่ใช่ตัวเลือกก็ตาม)

จากนั้นจำนวนข้อบกพร่องและการไม่สอดคล้องกับการใช้งานไม่กี่ครั้งทำให้เกิดปัญหาจำนวนหนึ่งกับรหัสนั้น

  • เนื่องจากข้อผิดพลาด, Solaris 10 pax(อย่างน้อย) ไม่ทำงานเมื่อใช้ร่วมกับ-rwl -sด้วยเหตุผลบางอย่างดูเหมือนว่าจะใช้การทดแทนกับทั้งเส้นทางเดิมและเส้นทางที่คัดลอก ดังนั้นข้างต้นก็จะพยายามที่จะทำบางอย่างแทนlink("dirB/file", "dirB/file")link("dirA/file", "dirB/file")
  • บน FreeBSD paxอย่าสร้างฮาร์ดลิงก์สำหรับไฟล์ประเภทsymlink (พฤติกรรมที่อนุญาตโดย POSIX) ไม่เพียงแค่นั้น แต่ยังใช้การทดแทนกับเป้าหมายของ symlink (พฤติกรรมที่ไม่ได้รับอนุญาตจาก POSIX) ดังนั้นสำหรับตัวอย่างเช่นถ้ามีfoo -> AAsymlink ในdirAก็จะกลายเป็นในfoo -> BAdirB

นอกจากนี้หากคุณต้องการทำสิ่งเดียวกัน แต่มีเส้นทางของไฟล์ที่มีเนื้อหาจัดเก็บอยู่$srcและ$dstสิ่งสำคัญคือการตระหนักว่าการpax -rwl -- "$src" "$dst"สร้างโครงสร้างไดเรกทอรีแบบเต็มของ$srcภายใน$dst(ต้องมีอยู่และเป็นไดเรกทอรี) ตัวอย่างเช่นถ้า$srcเป็นfoo/barแล้ว$dst/foo/barจะถูกสร้างขึ้น

หากคุณต้องการ$dstเป็นสำเนาของ$srcสิ่งที่ง่ายที่สุดน่าจะเป็น:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")

(ซึ่งจะแก้ไขปัญหาส่วนใหญ่ที่กล่าวถึงข้างต้น แต่จะล้มเหลวหากเส้นทางที่แน่นอนของการ$dstสิ้นสุดในตัวละครขึ้นบรรทัดใหม่)

ตอนนี้ที่จะไม่ช่วยในระบบ GNU / Linux paxที่ไม่มี

เป็นที่น่าสนใจที่จะทราบว่าpaxสร้างโดย POSIX เพื่อรวมคุณสมบัติของtarและcpioคำสั่ง

cpioเป็นประวัติศาสตร์คำสั่ง Unix (จาก 1977) เมื่อเทียบกับการประดิษฐ์ POSIX และมีการดำเนินงานของกนูเช่นกัน (ไม่ได้เป็นpaxอย่างใดอย่างหนึ่ง) ดังนั้นแม้ว่ามันจะไม่ได้เป็นคำสั่งมาตรฐานอีกต่อไป(มันอยู่ใน SUSv2) แต่มันก็ยังเป็นเรื่องธรรมดามากและมีชุดคุณสมบัติหลักที่คุณสามารถพึ่งพาได้

เทียบเท่าจะเป็นpax -rwl cpio -plอย่างไรก็ตาม:

  1. cpio รับรายการอินพุตไฟล์บน stdin ซึ่งต่างกับอาร์กิวเมนต์ (ตัวคั่น newline ซึ่งหมายความว่าไม่สนับสนุนชื่อไฟล์ที่มีอักขระบรรทัดใหม่)
  2. ไฟล์ทั้งหมดจะต้องมีการระบุ (โดยทั่วไปคุณฟีดมันเอาท์พุทของfind( findและcpioได้รับการพัฒนาร่วมกันโดยคนเดียวกัน))
  3. ข้อมูลเมตาไม่ได้รับการเก็บรักษาไว้ ( cpioการใช้งานบางอย่างมีตัวเลือกในการรักษาบางอย่าง แต่ไม่มีอะไรพกพาได้)

ดังนั้นด้วยcpio:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")

ดูเหมือนว่า -s / A / B / นั้นเฉพาะเจาะจงกับตัวอย่างของฉัน คุณจะทำอย่างไรถ้าชื่อไดเรกทอรีต้นทางและชื่อไดเรกทอรีเป้าหมายเป็นตัวแปร $ sourcedir และ $ targetdir
Gudmundur Orn

@GudmundurOrn ดูการแก้ไข
Stéphane Chazelas

ฉันรันคำสั่งนี้บน OS X และเพิ่งได้รับข้อความแสดงข้อผิดพลาด "pax: ไม่สามารถลิงก์ไฟล์. / a.txt กับตัวเอง" ฉันใช้คำสั่งของคุณอย่างแท้จริงเพียงแค่แทนที่ไดเรกทอรีต้นฉบับด้วยชื่อจริงโดยปล่อย / A / B และจุดสุดท้ายตามที่เป็นอยู่ ฉันเข้าใจอะไรผิดไปหรือเปล่า?
db

@db, -s /A/Bแทนที่Aด้วยBเพื่อที่จะกลายเป็นdirA dirBหากชื่อไดเรกทอรีต้นทางของคุณไม่มีAนั้นจะคัดลอก (ลิงค์) มันไปเอง ดูคำตอบที่เหลือสำหรับแนวทางที่ดีกว่า
Stéphane Chazelas


2

ในกรณีที่คุณกำลังมองหาที่คัดลอกด้วย hardlinksคุณลักษณะที่จะทำให้ภาพรวมหรือการสำรองข้อมูลของ (ทั้งหมดหรือบางส่วน) rsnapshotไฟล์ของคุณมีลักษณะที่


1
นั่นดูน่าสนใจ. แต่ฉันเดาว่าฮาร์ดลิงก์เป็นเพียงกลไกการถ่ายภาพที่ดีหากไฟล์จะไม่ถูกแก้ไข ขวา?
Gudmundur Orn

@Gudmundur Orn; สิ่งนี้ถูกต้อง เครื่องมือที่กล่าวถึงในคำตอบของฉันจะสร้างสแน็ปช็อตใหม่ในลักษณะที่ไฟล์ไม่ซ้ำกัน เช่นไฟล์ที่มีอยู่ (ไม่ได้แก้ไข) จะถูกสร้างเป็นลิงก์และไฟล์ใหม่ (หรือไฟล์ที่มีอยู่ในเวอร์ชันที่แก้ไข) จะถูกสร้างเป็นไฟล์ใหม่ ดังนั้นคุณจะมีความซ้ำซ้อนน้อยที่สุด
Janis

0

คำตอบของ @ gudmundur-orn นั้นถูกต้อง แต่ถ้าคุณอยู่บน BtrFS บน Linux cp a --reflink=auto dirA dirBควรทำเคล็ดลับด้วยความแตกต่างไฟล์ต่างกันจริง ๆ แล้วการเปลี่ยนอันหนึ่งไม่เปลี่ยนเลย คุณสามารถประสบความสำเร็จส่วนใหญ่เหมือนกันกับcp -cบน Mac ที่มี APFS ( autoจะทำสำเนาเต็มรูปแบบหากไม่สามารถทำได้-cจะล้มเหลว)

ระบบไฟล์ COW ใด ๆ ควรทำเช่นนั้นได้ แต่ผู้ขายไม่ได้ตกลงในตัวเลือกบรรทัดคำสั่งมาตรฐาน

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