Phá vỡ một liên kết cứng tại chỗ?


13

Tôi đang giữ các dotfiles của mình dưới sự kiểm soát phiên bản và tập lệnh triển khai chúng tạo ra các liên kết cứng. Tôi cũng sử dụng etckeeperđể đặt /etckiểm soát phiên bản của tôi . Gần đây tôi đã nhận được cảnh báo như thế này:

warning: hard-linked files could cause problems with bzr

Một bản sao đơn giản ( cp filename.ext filename.ext) sẽ không hoạt động:

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

Đổi tên / di chuyển tệp - ngoại trừ các tập - cũng không phá vỡ liên kết cứng.

Vì vậy, câu hỏi của tôi là: có cách nào để phá vỡ một liên kết cứng đến một tập tin mà không thực sự phải biết các liên kết cứng / s khác đến tập tin đó ở đâu không?


2
Lệnh "rm" phá vỡ các liên kết cứng.
Johan

Câu trả lời:


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

Làm cho nó thành kịch bản:

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

Thực hiện sao chép trước, sau đó di chuyển nó vào vị trí, có lợi thế là tệp nguyên tử thay đổi từ một liên kết cứng thành một bản sao riêng biệt (không có thời điểm filenamebị thiếu hoặc thiếu một phần thời gian ).


7

Bạn có thể có nghĩa là bạn muốn tách liên kết cứng thành một tệp độc lập, riêng biệt.

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

Một liên kết cứng là kết nối giữa một mục trong thư mục và khối inode trên đĩa.

Inodes lưu trữ siêu dữ liệu tệp và đối với các tệp nhỏ, một số hệ thống tệp lưu trữ dữ liệu trong nút, nếu không thì trỏ đến các khối dữ liệu và cho các tệp rất lớn danh sách gián tiếp và gián tiếp kép của các đơn vị phân bổ đĩa.

Bất kể, kết nối giữa tên tệp (đó là những gì lệnh ls tạo ra) và khối inode lưu trữ dữ liệu meta này, được gọi là một liên kết cứng.

Có nhiều liên kết cứng đến một tệp có nghĩa là cùng một nút được tham chiếu bởi nhiều mục nhập thư mục, có thể trong các thư mục khác nhau (trên một hệ thống tệp)

rm xóa mục nhập tên tệp từ thư mục. Khi một nút không còn được tham chiếu bởi bất kỳ tệp nào, không gian của nó sẽ được giải phóng để sử dụng bởi các tệp khác.


Thật. Đây là những gì cpmvví dụ ngụ ý. Vì vậy, không có cách nào xung quanh bằng cách sử dụng một tập tin tạm thời, tôi thấy.
0xC0000022L

@ 0xC0000022L, Không, các nút không chứa con trỏ đến các nút khác. Chỉ cần các khối dữ liệu (hoặc chúng có thể tăng gấp đôi không gian dữ liệu nếu đối tượng nhỏ).
vonbrand

4
Đảm bảo quyền và dữ liệu khác được giữ nguyên khi sao chép, tức là. sử dụng cp -a(ít nhất là lõi GNU).
vonbrand

@ 0xC0000022L, nếu bạn xem xét kỹ, chỉ có một tên tạm thời cho tệp gốc, một tệp mới chỉ được tạo ở bước cuối cùng.
vonbrand

@vonbrand Họ thực sự có thể, tùy thuộc vào hệ thống tập tin nào đang được sử dụng.
Johan

4

Đặt phần này vào cuối tệp ~ / .bashrc của bạn.

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

Chạy nó như thế này

delink filename

3

Cách tốt nhất để làm điều đó với một tập lệnh bash sẽ là như thế này:

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

điểm cần lưu ý:

  • kiểm tra xem tập tin có phải là tập tin thông thường hay không trước khi thử sao chép nó
  • giữ tập tin cũ tại chỗ cho đến khi bản sao đã sẵn sàng
  • sử dụng mktempđể tạo một tệp được đảm bảo không tồn tại
  • sử dụng -fđể buộc ghi đè và --preserve=allgiữ siêu dữ liệu giống nhất có thể với tệp gốc
  • sử dụng --"trích dẫn các đường dẫn chứa khoảng trắng và / hoặc bắt đầu bằng-

Thực hiện thay thế mà không tạo tệp tạm thời là không thể với các cuộc gọi hệ thống linux hiện tại (3.16): trong khi có thể ghi đè lên tệp một cách nguyên tử (nghĩa là xóa tệp cũ và thay thế bằng tệp mới dưới dạng một thao tác), nó không thể làm như vậy với một tệp không có tên trên hệ thống tệp (tức là tệp tạm thời được tạo bằng O_TMPFILEcờ openchức năng) vì renamehàm yêu cầu tên tệp làm đầu vào (không có phiên bản renamenào lấy đầu vào là mô tả tệp - xem tại đây để biết chi tiết)


1
Lưu ý rằng bạn không thể trích dẫn tên trong cuộc gọi dirnamemktempcuộc gọi của bạn . Đã sửa lỗi đó cho bạn ...
derobert

@derobert oh cảm ơn bạn, nhưng điều này sẽ không hoạt động vì có dấu ngoặc kép lồng nhau ... cần một sửa chữa khác! Kinda ghét bash
pqnet

3
Nó sẽ hoạt động vì $( ... )thay thế lệnh kiểu. Một lý do của nó đẹp hơn ` ... `phong cách.
derobert

@derobert tốt đẹp, không biết điều đó. Ngoài ra, làm thế nào bạn có thể sử dụng `bên trong các thẻ mã nội tuyến?
pqnet

Bạn có thể thoát khỏi chúng bằng dấu gạch chéo ngược. Vì vậy, để đưa `bạn vào: `\``(tất nhiên, tôi đã thoát hai lần để lấy nó để cho bạn thấy những gì bạn gõ).
derobert

-1

Lệnh bạn đang tìm là unlink


Có lẽ câu hỏi của tôi không rõ ràng, nhưng bởi "tại chỗ" và các ví dụ với cpmvtôi muốn nói rõ rằng tôi muốn tập tin tồn tại sau đó.
0xC0000022L

À, tôi không thấy rõ điều đó, không. Bạn nên đi với câu trả lời của Johan.
Jenny D

1
Lệnh "hủy liên kết" chỉ đơn giản là loại bỏ tệp (những gì cuộc gọi hệ thống unlink () thực hiện).
Raúl Salinas-Monteagudo

-1

Nếu bạn đang tìm kiếm tất cả các tên tệp là liên kết cứng đến tệp này thì bạn có thể sử dụng:

find -samefile myknowhardlinkfile

cũng ls -il myknowhardlinkfilesẽ hiển thị cho bạn số lượng tên tệp được liên kết cứng đến cùng một nút (trường thứ ba).

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

Điều này không thực sự trả lời câu hỏi, mặc dù nó có thể hữu ích.
Flimm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.