ทำลายฮาร์ดลิงก์ทั้งหมดภายในโฟลเดอร์


10

ฉันมีโฟลเดอร์ที่มีไฟล์จำนวนหนึ่งซึ่งมีฮาร์ดลิงก์ (ในโฟลเดอร์เดียวกันหรือที่อื่น) และฉันต้องการยกเลิกการเชื่อมโยงไฟล์เหล่านี้ดังนั้นพวกเขาจึงเป็นอิสระและการเปลี่ยนแปลงเนื้อหาจะไม่มีผลใด ๆ ไฟล์อื่น ๆ (จำนวนลิงก์ของพวกเขากลายเป็น 1)

ด้านล่างนี้ฉันให้วิธีแก้ปัญหาซึ่งโดยทั่วไปจะคัดลอกฮาร์ดลิงก์แต่ละลิงก์ไปยังตำแหน่งอื่นจากนั้นย้ายกลับมาที่เดิม

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

คำตอบที่หยาบ:

ค้นหาไฟล์ที่มีฮาร์ดลิงก์ ( แก้ไข : หากต้องการค้นหาซ็อกเก็ต ฯลฯ ที่มีฮาร์ดลิงก์ให้ใช้find -not -type d -links +1):

find      -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.

วิธีหยั่งรู้ในการยกเลิกการเชื่อมโยงไฟล์ (คัดลอกไปยังตำแหน่งอื่นและย้ายกลับ): แก้ไข: ดัง ที่ Celada กล่าวว่าควรทำ cp -p ด้านล่างเพื่อหลีกเลี่ยงการสูญเสียเวลาและการอนุญาต แก้ไข: สร้างไดเรกทอรีชั่วคราวและคัดลอกไปยังไฟล์ที่อยู่ใต้แทนที่จะเขียนทับไฟล์ temp มันลดความเสี่ยงในการเขียนทับข้อมูลบางส่วนแม้ว่าmvคำสั่งจะยังคงมีความเสี่ยง (ขอบคุณ @Tobu) แก้ไข: พยายามสร้างไดเรกทอรีชั่วคราวในระบบไฟล์เดียวกัน (@MikkoRantalainen)

# This is unhardlink.sh
set -e
for i in "$@"; do
  temp="$(mktemp -d -- "${i%/*}/hardlnk-XXXXXXXX")"
  [ -e "$temp" ] && cp -ip "$i" "$temp/tempcopy" && mv "$temp/tempcopy" "$i" && rmdir "$temp"
done

ดังนั้นหากต้องการยกเลิกการเชื่อมโยงฮาร์ดลิงก์ทั้งหมด ( แก้ไข : เปลี่ยน-type fเป็น-not -type dดูด้านบน):

find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh

ฉันไม่คิดว่า 'น้ำมันดิบ' วิธีเดียวที่จะทำให้เร็วขึ้นนั้นน่าจะเป็นการหลอกลวงด้วยการเรียกระบบ sendfile () และยกเลิกการเชื่อมโยงไฟล์โอเพนซอร์สและเขียนเป้าหมายใหม่ในสถานที่ ตรงไปตรงมามันไม่คุ้มค่ากับความพยายามแม้ว่า
Matthew Ife

โดย 'หยาบคาย' ฉันหมายถึงตัวอย่างเช่นเมื่อฉันรันคำสั่งนี้โดยใช้cp -iสวิตช์มันจะถ่มน้ำลายใส่ฉันสองสามข้อความเพื่อถามว่าควรแทนที่./fileXXXXXX( $tempไฟล์) แม้ว่า tmpfile ควรให้ชื่อไฟล์ที่ไม่ซ้ำดังนั้นจึงต้องเป็นสภาพการแข่งขันบางอย่างหรืออะไรก็ตามและด้วยความเสี่ยงที่จะสูญเสียข้อมูลบางส่วน
Suzanne Dupéron

1
เป็นเรื่องปกติที่ไฟล์นั้นมีอยู่คุณเพิ่งสร้างไฟล์ด้วย tempfile (nb: เลิกใช้แล้วในความโปรดปรานของ mktemp แต่นั่นไม่ใช่สิ่งที่ทำให้เกิดปัญหาของคุณ)
Tobu

1
คุณunhardlink.shควรสร้างไดเรกทอรีชั่วคราวภายในไดเรกทอรีเดียวกันที่มีไฟล์ที่ต้องยกเลิกการเชื่อมโยง มิฉะนั้นการเรียกซ้ำของคุณอาจเรียกคืนภายในระบบไฟล์อื่นและคุณจะย้ายสิ่งต่างๆไปตามขอบเขตของระบบไฟล์เนื่องจากไดเรกทอรีชั่วคราวของคุณอยู่ที่ไดเรกทอรีทำงานปัจจุบัน ฉันเดาว่าคุณสามารถผ่าน"$(dirname "$i")/hardlink-XXXXXX"เป็นอาร์กิวเมนต์ให้ mktemp แทน
Mikko Rantalainen

1
@MikkoRantalainen ขอบคุณมากอัปเดต! โปรดทราบว่าหากระบบไฟล์เป็นบางประเภทของ unionfs หรือfuseระบบไฟล์จริง ๆ แล้วมันอาจส่งpath/to/hardlink-XXXไปยังสื่อเก็บข้อมูลจริงที่แตกต่างกันกว่าpath/to/original-fileแต่มีไม่มากที่สามารถทำได้เกี่ยวกับเรื่องนี้
Suzanne Dupéron

คำตอบ:


9

มีห้องสำหรับการปรับปรุงในสคริปต์ของคุณตัวอย่างเช่นการเพิ่ม-pตัวเลือกในcpคำสั่งเพื่อให้สิทธิ์และการประทับเวลาจะถูกเก็บไว้ในการดำเนินการ unhardlink และคุณสามารถเพิ่มการจัดการข้อผิดพลาดบางอย่างเพื่อให้ไฟล์ temp ถูกลบในกรณีที่เกิดข้อผิดพลาด แต่แนวคิดพื้นฐานของการแก้ปัญหาของคุณเป็นแนวคิดเดียวที่จะทำงานได้ หากต้องการยกเลิกการเชื่อมโยงไฟล์คุณจะต้องคัดลอกแล้วย้ายสำเนากลับไปที่ชื่อเดิม ไม่มีวิธีแก้ปัญหา "หยาบคายน้อยลง" และโซลูชันนี้มีเงื่อนไขการแข่งขันในกรณีที่กระบวนการอื่นกำลังเข้าถึงไฟล์ในเวลาเดียวกัน


อันที่จริงฉันมักจะใช้ cp -a เมื่อคัดลอกเนื้อหาเพื่อรักษาทุกอย่างชดเชยและคัดลอก symlink เป็น symlink ไม่รู้ว่าทำไมฉันถึงลืมมันในเวลานี้ แต่หลังจากเห็นคำตอบของคุณฉันเข้าใจว่าฉันเมาหมดเวลาแล้วและต้อง (กู้คืนอย่างเจ็บปวด) จากการสำรองข้อมูล
Suzanne Dupéron

5

หากคุณต้องการเบิร์นพื้นที่ดิสก์และคุณมีรุ่นที่ค่อนข้างทันสมัยtar(เช่นมีอะไรใน Ubuntu 10.04 และ CentOS 6) คุณสามารถเล่นกับ--hard-dereferenceตัวเลือกได้

สิ่งที่ต้องการ:

$ cd /path/to/directory
$ ls -l *
bar:
total 12
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 2 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 2 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

(ที่ฉันเคยวิ่งln foo/[12] bar)

$ tar cvf /tmp/dereferencing.tar --hard-dereference .
$ tar xvf /tmp/dereferencing.tar
$ ls -l *
bar:
total 12
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 3

foo:
total 12
-rw-rw-r-- 1 cjc cjc 3 May  6 19:07 1
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 2
-rw-rw-r-- 1 cjc cjc 2 May  6 19:07 4

จากหน้าคน:

   --hard-dereference
          follow hard links; archive and dump the files they refer to

ฉันสงสัยว่ามีน้ำมันดินเล็กน้อยไม่สามารถทำได้ การแก้ไขที่ดี
Joseph Kern

ฉันลืมที่จะพูดถึงว่าฉันมีพื้นที่ว่างในดิสก์ไม่เพียงพอที่จะคัดลอกทุกอย่าง โดยทั่วไปวิธีการของคุณจะเหมือนกับcp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folderถ้าฉันไม่ผิด ฉันคิดว่าวิธีการของคุณจะมีประสิทธิภาพมากขึ้น แต่เนื่องจาก tar จะเกี่ยวข้องกับการค้นหาดิสก์น้อยลงดังนั้นการ thrashing น้อยลง หนึ่งสามารถบรรลุเดียวกันกับ rsync ด้วยประสิทธิภาพที่ต่ำกว่าวิธี cp :)
Suzanne Dupéron

1
เพื่อหลีกเลี่ยงการใช้ดิสก์พิเศษมากอาจเป็นไปได้ที่จะเรียกใช้บางอย่างเช่นtar cvf - --hard-dereference . | tar xf -แต่อาจมีสภาวะการแย่งชิงที่จะทำให้สิ่งต่าง ๆ เกิดการระเบิด ฉันยังไม่ได้ลองเลยและตอนนี้ฉันก็ไม่อยากทำเช่นนั้น
cjc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.