ทำลายการเชื่อมโยงอย่างหนักในสถานที่?


13

ฉันคง dotfiles ของฉันไว้ภายใต้การควบคุมเวอร์ชันและสคริปต์ที่ปรับใช้สร้างการเชื่อมโยงอย่างหนัก ฉันยังใช้etckeeperเพื่อ/etcควบคุมเวอร์ชันของฉัน เมื่อเร็ว ๆ นี้ฉันได้รับคำเตือนแบบนี้:

warning: hard-linked files could cause problems with bzr

สำเนาธรรมดา ( cp filename.ext filename.ext) จะไม่ทำงาน:

cp: `filename.ext' and `filename.ext' are the same file

การเปลี่ยนชื่อ / ย้ายไฟล์ - ยกเว้นในไดรฟ์ข้อมูล - ไม่ทำลายฮาร์ดลิงก์

ดังนั้นคำถามของฉันคือ: มีวิธีที่จะทำลายฮาร์ดลิงก์ไปยังไฟล์โดยไม่ต้องรู้ว่าฮาร์ดลิงค์อื่น ๆ / s ไปยังไฟล์นั้นอยู่ที่ไหน?


2
คำสั่ง "rm" แบ่งการเชื่อมโยงอย่างหนัก
Johan

คำตอบ:


14
cp -p filename filename.tmp
mv -f filename.tmp filename

ทำให้เป็นสคริปต์:

dir=$(dirname -- "$filename")
tmp=$(TMPDIR=$dir mktemp)
cp -p -- "$filename" "$tmp"
mv -f -- "$tmp" "$filename"

การทำสำเนาก่อนจากนั้นย้ายเข้าที่มีข้อดีที่ไฟล์อะตอมเปลี่ยนแปลงจากการเป็นฮาร์ดลิงก์ไปเป็นสำเนาแยกต่างหาก (ไม่มีจุดในเวลาที่filenameบางส่วนหรือหายไป)


7

คุณอาจหมายความว่าคุณต้องการแยกฮาร์ดลิงก์ออกเป็นไฟล์อิสระแยกต่างหาก

mv hardlink tempname && cp tempname hardlink && rm tempname

ฮาร์ดลิงก์คือการเชื่อมต่อระหว่างรายการในไดเรกทอรีและบล็อก inode บนดิสก์

inodes เก็บ meta-data ของไฟล์และสำหรับไฟล์ขนาดเล็กระบบไฟล์บางระบบจะเก็บข้อมูลใน inode มิฉะนั้นพอยน์เตอร์จะชี้ไปที่บล็อกข้อมูลและสำหรับไฟล์ที่มีขนาดใหญ่มาก

โดยไม่คำนึงถึงการเชื่อมต่อระหว่างชื่อไฟล์ (ซึ่งเป็นสิ่งที่คำสั่ง ls ผลิต) และบล็อก inode ซึ่งเก็บเมตาดาต้านี้เรียกว่าฮาร์ดลิงค์

การมีฮาร์ดลิงก์หลายลิงก์ไปยังไฟล์เดียวหมายถึงไอโหนดเดียวกันที่อ้างอิงโดยรายการไดเรกทอรีมากกว่าหนึ่งรายการอาจอยู่ในไดเรกทอรีที่ต่างกัน (ในระบบไฟล์เดียว)

rm ลบรายการชื่อไฟล์จากไดเร็กทอรี เมื่อ inode ไม่ได้ถูกอ้างอิงโดยไฟล์ใด ๆ อีกต่อไปพื้นที่ว่างนั้นจะถูกปล่อยให้ใช้งานโดยไฟล์อื่น ๆ


จริง นี่คือสิ่งที่cpและmvตัวอย่างที่บอกเป็นนัย ฉันไม่เห็นวิธีการใช้ไฟล์ชั่วคราว
0xC0000022L

@ 0xC0000022L, ไม่, inodes ไม่มีพอยน์เตอร์ไปยัง inodes อื่น ๆ เพียงเพื่อบล็อกข้อมูล (หรือพวกเขาสามารถเป็นสองเท่าของพื้นที่ข้อมูลถ้าวัตถุมีขนาดเล็ก)
vonbrand

4
ตรวจสอบให้แน่ใจว่าการอนุญาตและข้อมูลอื่น ๆ ได้รับการสงวนไว้เมื่อคัดลอกเช่น ใช้cp -a(อย่างน้อย coreutils GNU)
vonbrand

@ 0xC0000022L ถ้าคุณดูอย่างระมัดระวังมีเพียงชื่อชั่วคราวสำหรับไฟล์เดิมไฟล์ใหม่จะถูกสร้างขึ้นในขั้นตอนสุดท้ายเท่านั้น
vonbrand

@ vonbrand พวกเขาสามารถขึ้นอยู่กับระบบไฟล์ที่ถูกใช้
Johan

4

วางสิ่งนี้ไว้ท้ายไฟล์ ~ / .bashrc ของคุณ

delink () { tmpfile="$1$(date)"; cp -a "$1" "$tmpfile"; mv "$tmpfile" "$1"; }

เรียกใช้แบบนี้

delink filename

3

วิธีที่ดีที่สุดในการทำสคริปต์ทุบตีจะเป็นดังนี้:

if [ -f "$1" ] ; then
dir="$(dirname -- "$1")"
tmpfile="$(mktemp --tmpdir="$dir")"
cp --preserve=all -f -- "$1" "$tmpfile"
mv -f -- "$tmpfile" "$1"
fi

คะแนนที่ควรทราบ:

  • ตรวจสอบว่าไฟล์เป็นไฟล์ปกติก่อนที่จะพยายามคัดลอก
  • เก็บไฟล์เก่าไว้จนกว่าการคัดลอกจะพร้อม
  • ใช้mktempเพื่อสร้างไฟล์ที่รับประกันว่าจะไม่มีอยู่
  • ใช้-fเพื่อบังคับให้เขียนทับและ--preserve=allเก็บข้อมูลเมตาให้ใกล้เคียงกับไฟล์ต้นฉบับมากที่สุด
  • ใช้--และ"เพื่ออ้างอิงเส้นทางที่มีช่องว่างและ / หรือขึ้นต้นด้วย-

การทำการแทนที่โดยไม่สร้างไฟล์ชั่วคราวไม่สามารถทำได้ด้วยการเรียกระบบปัจจุบันของลินุกซ์ (3.16): ในขณะที่สามารถเขียนทับไฟล์แบบอะตอมมิก (เช่นลบไฟล์เก่าและแทนที่ด้วยไฟล์ใหม่เป็นการดำเนินการครั้งเดียว) เป็นไปไม่ได้ที่จะทำเช่นนั้นกับไฟล์ที่ไม่มีชื่อในระบบไฟล์ (เช่นไฟล์ชั่วคราวที่สร้างขึ้นโดยใช้ฟังก์ชั่นO_TMPFILEธงopen) เพราะrenameฟังก์ชั่นนี้ต้องการชื่อไฟล์เป็นอินพุต (ไม่มีรุ่นrenameที่ใช้เป็นไฟล์อธิบายไฟล์ - ดูรายละเอียดที่นี่ )


1
โปรดทราบว่าคุณไม่สามารถพูดชื่อdirnameและการmktempโทรของคุณได้ แก้ไขที่สำหรับคุณ ...
Derobert

@derobert โอ้ขอบคุณ แต่นี่ใช้ไม่ได้เพราะมีคำพูดซ้อนซ้อนอยู่ ... ต้องการการแก้ไขอีกครั้ง! Kinda เกลียดชังทุบตี
pqnet

3
มันจะทำงานได้เนื่องจากการ$( ... )ทดแทนคำสั่ง -style เหตุผลหนึ่งที่ดีกว่า` ... `สไตล์
Derobert

@derobert ดีไม่รู้ว่า นอกจากนี้คุณสามารถใช้ `ภายในแท็กรหัสแบบอินไลน์ได้อย่างไร
pqnet

คุณสามารถหลบหนีด้วยแบ็กสแลช ดังนั้นเพื่อให้`คุณใส่: `\``(แน่นอนฉันหนีสองครั้งที่จะได้รับมันเพื่อแสดงสิ่งที่คุณพิมพ์)
Derobert

-1

คำสั่งที่คุณต้องการคือ unlink


บางทีคำถามของฉันอาจไม่ชัดเจน แต่โดย "แทนที่" และตัวอย่างที่มีcpและmvฉันตั้งใจจะทำให้ชัดเจนว่าฉันต้องการไฟล์ที่มีอยู่หลังจากนั้น
0xC0000022L

อ่าฉันไม่เห็นชัดเจนขนาดนั้นเลย คุณควรไปกับคำตอบของโจฮานแล้ว
เจนนี่ D

1
คำสั่ง "unlink" เพียงแค่ลบไฟล์ (สิ่งที่ unlink () เรียกระบบ)
Raúl Salinas-Monteagudo

-1

หากคุณกำลังมองหาชื่อไฟล์ทั้งหมดที่เป็นฮาร์ดลิงก์ไปยังไฟล์นี้คุณสามารถใช้:

find -samefile myknowhardlinkfile

นอกจากนี้ยังls -il myknowhardlinkfileจะแสดงจำนวนชื่อไฟล์ hardlinked เพื่อ inode เดียวกัน (เขตที่สาม)

101612442 -rw-rw-r--. 2 me me 0 Aug  5 07:07 myknowhardlinkfile

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