Xóa tệp, nhưng chỉ khi đó là một liên kết tượng trưng


11

Lý tưởng nhất là tôi muốn một lệnh như thế này

rm --only-if-symlink link-to-file

bởi vì tôi đã tự đốt quá nhiều lần vô tình xóa tệp thay vì liên kết tượng trưng trỏ đến tệp. Điều này có thể đặc biệt xấu khi sudo có liên quan. Bây giờ tôi tất nhiên làm một ls -alđể đảm bảo rằng nó thực sự là một liên kết tượng trưng và như vậy nhưng nó dễ bị lỗi của nhà điều hành (tệp có tên tương tự, lỗi đánh máy, v.v.) và điều kiện cuộc đua (nếu ai đó muốn tôi xóa một tệp vì một số lý do). Có cách nào để kiểm tra xem một tập tin có phải là một liên kết tượng trưng không và chỉ xóa nó nếu nó nằm trong một lệnh?


1
Tôi không nghĩ rằng điều kiện cuộc đua nên là một mối quan tâm. Bất kỳ ai có thể xóa symlink và thay thế nó bằng một tệp sẽ cần có quyền ghi trên thư mục, điều đó có nghĩa là họ cũng có thể tự xóa tệp.
Nate Eldredge

Câu trả lời:


19
 $ rm_if_link(){ [ ! -L "$1" ] || rm -v "$1"; }

 #test
 $ touch nonlink; ln -s link
 $ rm_if_link nonlink
 $ rm_if_link link
   removed 'link'     

4
Chắc chắn sẽ rõ ràng hơn để loại bỏ !và thay đổi ||thành&&
glenn jackman

5
@glennjackman Tôi đã tạo thói quen thích ||hình thức này. &&mang mọi thứ xuống nếu bạn đang ở set -echế độ.
PSkocik

@PSkocik Nói chung, đó là rủi ro vì nó không phân biệt giữa trường hợp thú vị (tệp tồn tại và là một liên kết tượng trưng) và các lý do khác cho mã thoát không khác, chẳng hạn như giá trị không được trích dẫn ( [ ! -L $1 ]), sử dụng toán tử không hợp lệ ( [ ! -l foo ]) hoặc thậm chí lỗi cú pháp ( [ ! -q foo || echo foo)
l0b0

2
@XiongChiamiov Vấn đề với rm_if_link(){ [ -L "$1" ] && rm -v "$1"; }là việc chạy nó trên một set -e chế độ không liên kết trong chế độ sẽ giết chết quá trình shell của bạn. Bạn có thể nối thêm || :nhưng sau đó, nó trở thành, IMHO, thậm chí ít rõ ràng hơn ! ||phiên bản, và nó sẽ ngăn chặn một rmthất bại giết chết bạn set -e, điều có thể không mong muốn. ! ||là khá ngắn gọn và rõ ràng, và không gặp phải bất kỳ vấn đề nào trong số này.
PSkocik

1
Không . Các tùy chọn khác: a) đặt rmbên trong thử nghiệm của bạn, b) sử dụng câu lệnh if thực tế, c) không đi xung quanh bằng cách sử dụng -ebên trong vỏ tương tác (và kiểm tra tập lệnh của bạn!). Nếu bạn muốn tranh luận về khả năng đọc, sử dụng ifđể kiểm tra nếu một cái gì đó là một liên kết khá rõ ràng là người chiến thắng.
Tẩy chay SE cho Monica Cellio

5

Bạn có thể sử dụng find-type lđiều kiện kiểm tra của nó (kiểm tra xem đối tượng tìm thấy có phải là mực l hay không)

Ví dụ: nếu bạn có một tệp được gọi footrong thư mục hiện tại, bạn có thể làm điều này:

$ find . -type l -iname "foo" -delete

Bạn có thể đơn giản hóa điều đó chỉ bằng:

$ find . -maxdepth 1 -type l -delete

Mà sẽ xóa tất cả các liên kết tượng trưng trong thư mục hiện tại.

Cảnh báo:

Các -deletetùy chọn trong findlà thực sự nguy hiểm. HÃY ĐẾN NƠI NƠI Ở KẾT THÚC TÌM KIẾM. Nếu bạn đặt sai vị trí, nó sẽ xóa mọi thứ nó tìm thấy bất kể kết quả có khớp với điều kiện của bạn hay không.

Như đã đề xuất trong các nhận xét, một tùy chọn an toàn hơn có thể được sử dụng findrm -i(buộc bạn phải xác nhận xóa tệp) trong kết hợp:

$ $ find . -type l -iname "foo" | xargs rm -i

Cá nhân tôi sử dụng -exec trash {} \;để tạm thời xóa các tập tin, bởi vì tôi, giống như bạn, đã bị đốt cháy rmtrong quá khứ. Double đi cho một -deletelá cờ thất lạc .

http://slackermedia.ml/trashy


1
Thay vì -delete bạn chỉ có thể in nó và chuyển nó đến xargs: find . -type l -iname "foo" | xargs rm -i an toàn hơn.
Boban P.

1
Chắc chắn tôi thích sử dụng rm -ian toàn cho mọi người.
Klaatu von Schlacker

3
"Điều này sẽ xóa tất cả các liên kết tượng trưng trong thư mục hiện tại" ... và bất kỳ điểm nào bên dưới nó.
Joseph R.

1
Như @JosephR. cho biết, nó sẽ đi tất cả các con đường xuống. Thêm -maxdepth 1 trong tìm kiếm.
Boban P.

1
Vẫn phá vỡ tên tập tin với không gian. Đề xuất sử dụng -print0cho find-0cho xargs.
Wildcard

4
zsh -c 'rm foo(@)'

@vòng loại toàn cầu ; mô hình foo(@)phù hợp với những gì foophù hợp, nhưng chỉ các liên kết tượng trưng.

foo(-@)sẽ chỉ phù hợp với các liên kết tượng trưng bị hỏng. foo(@,L0)sẽ chỉ phù hợp với các liên kết tượng trưng và các tập tin trống.

Tất nhiên, nếu bạn đang chạy zsh ở nơi đầu tiên, bạn chỉ cần gõ rm foo(@). Bạn cần lưu ý không nhấn Entertrước khi gõ (@).


1
Zsh âm thanh ngày càng mạnh mẽ hơn khi tôi thấy câu trả lời như thế này.
Jeff Schaller
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.