Phá vỡ tất cả các liên kết cứng trong một thư mục


10

Tôi có một thư mục chứa một số tệp nhất định có liên kết cứng (trong cùng thư mục hoặc ở nơi khác) và tôi muốn hủy liên kết các tệp này để chúng trở nên độc lập và thay đổi nội dung của chúng sẽ không ảnh hưởng đến tập tin khác (số liên kết của họ trở thành 1).

Dưới đây, tôi đưa ra một giải pháp về cơ bản sao chép từng liên kết cứng đến một vị trí khác, sau đó di chuyển nó trở lại vị trí.

Tuy nhiên phương pháp này có vẻ khá thô sơ và dễ bị lỗi, vì vậy tôi muốn biết liệu có một lệnh nào đó sẽ hủy liên kết một tệp cho tôi không.

Câu trả lời thô thiển:

Tìm tệp có liên kết cứng ( Chỉnh sửa : Để tìm ổ cắm, v.v. có liên kết cứng, hãy sử dụng find -not -type d -links +1):

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

Một phương pháp thô sơ để hủy liên kết một tệp (sao chép nó sang vị trí khác và di chuyển nó trở lại): Chỉnh sửa: Như Celada đã nói, tốt nhất nên thực hiện một cp -p bên dưới, để tránh mất dấu thời gian và quyền. Chỉnh sửa: Tạo một thư mục tạm thời và sao chép vào một tệp trong đó, thay vì ghi đè lên tệp tạm thời, nó giảm thiểu rủi ro để ghi đè lên một số dữ liệu, mặc dù mvlệnh vẫn còn rủi ro (cảm ơn @Tobu). Chỉnh sửa: Cố gắng tạo thư mục tạm thời trong cùng hệ thống tệp (@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

Vì vậy, để bỏ liên kết cứng tất cả các liên kết cứng ( Chỉnh sửa : đã đổi -type fthành -not -type d, xem ở trên):

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

Tôi sẽ không coi đó là 'thô'. Cách duy nhất để có được điều đó nhanh hơn có lẽ là thực hiện một số mẹo với lệnh gọi hệ thống sendfile () và hủy liên kết tệp nguồn mở và viết lại mục tiêu tại chỗ. Thành thật mà nói nó không đáng nỗ lực mặc dù.
Matthew Ife

Theo 'thô', ý tôi là, ví dụ, khi tôi chạy lệnh này bằng cách sử dụng công cp -itắc, nó sẽ nhổ vào tôi một vài tin nhắn hỏi liệu nó có nên ghi đè ./fileXXXXXX( $temptệp) hay không, mặc dù tmpfile nên đặt tên tệp duy nhất, do đó phải là một loại điều kiện chủng tộc hoặc bất cứ điều gì, và với nó có nguy cơ mất một số dữ liệu.
Suzanne Dupéron

1
Việc tệp tồn tại là bình thường, bạn chỉ cần tạo nó bằng tempfile (nb: không dùng để ủng hộ mktemp, nhưng đó không phải là nguyên nhân gây ra sự cố của bạn).
Tobu

1
Bạn unhardlink.shnên tạo thư mục tạm thời trong cùng thư mục chứa tệp cần được liên kết. Mặt khác, cuộc gọi đệ quy của bạn có thể lặp lại bên trong một hệ thống tệp khác và cuối cùng bạn sẽ chuyển công cụ qua ranh giới hệ thống tệp vì thư mục tạm thời của bạn nằm trong thư mục làm việc hiện tại. Tôi đoán bạn có thể chuyển "$(dirname "$i")/hardlink-XXXXXX"như là đối số cho mktemp thay thế.
Mikko Rantalainen

1
@MikkoRantalainen Cảm ơn rất nhiều, đã cập nhật! Lưu ý rằng nếu hệ thống tệp là một loại kết hợp hoặc fusehệ thống tệp, nó thực sự có thể gửi path/to/hardlink-XXXđến một phương tiện lưu trữ vật lý khác path/to/original-file, nhưng không có nhiều điều có thể làm được về điều đó.
Suzanne Dupéron

Câu trả lời:


9

Có chỗ để cải thiện tập lệnh của bạn, ví dụ: thêm -ptùy chọn vào cplệnh để các quyền và dấu thời gian sẽ được giữ nguyên trong hoạt động không liên kết và bạn có thể thêm một số xử lý lỗi để tệp tạm thời bị xóa trong trường hợp có lỗi, nhưng ý tưởng cơ bản về giải pháp của bạn là cách duy nhất sẽ hoạt động. Để hủy liên kết một tập tin, bạn phải sao chép nó và sau đó di chuyển bản sao trở lại tên ban đầu. Không có giải pháp "ít thô thiển" hơn và giải pháp này có điều kiện chủng tộc trong trường hợp một quá trình khác đang truy cập tệp cùng một lúc.


Thật vậy, tôi luôn sử dụng cp -a khi sao chép nội dung, để bảo toàn mọi thứ, lặp lại và sao chép liên kết tượng trưng dưới dạng liên kết tượng trưng. Không biết tại sao tôi lại quên nó lần này, nhưng sau khi thấy câu trả lời của bạn, tôi hiểu rằng tôi đã làm hỏng tất cả các dấu thời gian của mình và phải (khá đau đớn) khôi phục chúng từ bản sao lưu.
Suzanne Dupéron

5

Nếu bạn muốn đốt hết dung lượng ổ đĩa và bạn có phiên bản tương đối hiện đại tar(ví dụ: những gì trên Ubuntu 10.04 và CentOS 6), bạn có thể chơi với --hard-dereferencetùy chọn này.

Cái gì đó như:

$ 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

(nơi tôi đã chạy 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

Từ trang người đàn ông:

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

Tôi nghi ngờ có rất ít tar không thể làm. Sửa chữa tốt đẹp.
Joseph Kern

Tôi quên đề cập rằng tôi không có đủ dung lượng đĩa để sao chép mọi thứ. Về cơ bản, phương pháp của bạn giống như cp -a --no-preserve=links /path/to/folder /path/to/copy && rm -rf /path/to/folder && mv /path/to/copy /path/to/folder, nếu tôi không nhầm. Tôi đoán rằng phương pháp của bạn sẽ hiệu quả hơn, tuy nhiên, vì tar sẽ liên quan đến việc tìm kiếm đĩa ít hơn, do đó ít bị đập hơn. Người ta có thể đạt được điều tương tự với rsync, với hiệu suất thậm chí thấp hơn phương thức cp :).
Suzanne Dupéron

1
Để tránh sử dụng nhiều đĩa phụ, có thể chạy một cái gì đó giống như tar cvf - --hard-dereference . | tar xf -nhưng có thể có một điều kiện cuộc đua sẽ khiến mọi thứ bùng nổ. Tôi đã không thử nó, và tôi không thích làm điều đó vào lúc này.
cjc
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.