Thay thế các liên kết tượng trưng bằng các tập tin


31

Có cách nào dễ dàng để thay thế tất cả các liên kết tượng trưng bằng tệp mà họ liên kết đến không?


3
Vấn đề gì bạn đang cố gắng giải quyết?
Daniel Beck

3
Tôi có một loạt các liên kết tượng trưng đến một ổ đĩa khác. Tôi cần di chuyển tất cả các tệp ra khỏi ổ đĩa được tham chiếu ở nơi khác để tôi có thể xóa nó.
Marty Trenouth

Câu trả lời:


14

Đối với một số định nghĩa của "dễ dàng":

#!/bin/sh
set -e
for link; do
    test -h "$link" || continue

    dir=$(dirname "$link")
    reltarget=$(readlink "$link")
    case $reltarget in
        /*) abstarget=$reltarget;;
        *)  abstarget=$dir/$reltarget;;
    esac

    rm -fv "$link"
    cp -afv "$abstarget" "$link" || {
        # on failure, restore the symlink
        rm -rfv "$link"
        ln -sfv "$reltarget" "$link"
    }
done

Chạy tập lệnh này với tên liên kết làm đối số, ví dụ thông qua find . -type l -exec /path/tos/script {} +


2
Cảm ơn đã sửa, anon, nhưng kịch bản không xử lý tên tập tin với không gian tốt, bằng cách trích dẫn các biến trong tất cả những nơi cần thiết. Thay đổi "$var"thành "${var}"noop trong sh / bash. Tôi đã xóa một bashism ( [[), phần còn lại tương thích với POSIX sh.
grawity

Một phương pháp thậm chí còn mạnh mẽ hơn để xử lý các lỗi liên kết tượng trưng là cpgửi một tệp tạm thời trong cùng thư mục sau đó mv -ftệp tạm thời đó vào bản gốc. Điều này sẽ bảo vệ chống lại các vấn đề như mọi người nhấn giữ Ctrl-Choặc hệ thống tập tin lấp đầy giữa các lệnh rmcp(do đó ngăn chặn ngay cả cái mới hoạt lnđộng). Tên tệp tạm thời rất dễ phát hiện ls -ađể dọn dẹp sau nếu cần.
Ông Fooz

Là một lưu ý phụ, tôi thực sự không thể nhớ tại sao tôi không chỉ sử dụng abstarget=$(readlink -f "$link")thay vì khối vụ án , nhưng đó có thể là lý do tính di động.
grawity

17

Có thể dễ dàng hơn khi chỉ sử dụng tar để sao chép dữ liệu vào một thư mục mới.

-H      (c and r mode only) Symbolic links named on the command line will
        be followed; the target of the link will be archived, not the
        link itself.

Bạn có thể sử dụng một cái gì đó như thế này

tar -hcf - sourcedir | tar -xf - -C newdir

tar --help:
-H, --format=FORMAT        create archive of the given format
-h, --dereference          follow symlinks; archive and dump the files they point to

1
Tôi yêu giải pháp của bạn, nhưng tôi không hiểu phần cuối của tin nhắn của bạn. Đối với tôi, bạn nên làm:tar -hcf - sourcedir | tar -xf - -C newdir
Seb DA ROCHA

1
Đồng ý, câu trả lời này sẽ cần cập nhật theo nhận xét.
astabada

1
cp -Llà giải pháp đơn giản hơn
plesiv

@plesiv true và tuân thủ posix, nhưng không phải tất cả các cpcài đặt sẽ sao chép các thư mục.
Wyatt8740

16

Nếu tôi hiểu bạn một cách chính xác, -Lcờ của cplệnh sẽ làm chính xác những gì bạn muốn.

Chỉ cần sao chép tất cả các liên kết tượng trưng và nó sẽ thay thế chúng bằng các tệp mà chúng trỏ đến.


4
Cảm ơn - gần như những gì tôi cần: Tôi đã phải làm một cái gì đó như: cp -L files tmp/ && rm files && cp tmp/files . Nếu bạn làm rõ, có lẽ bạn sẽ giúp được nhiều người hơn ...
hiền nhân

5

"Dễ dàng" sẽ là một chức năng của bạn, rất có thể.

Có lẽ tôi sẽ viết một tập lệnh sử dụng tiện ích dòng lệnh "find" để tìm các tệp được liên kết tượng trưng, ​​sau đó gọi rm và cp để xóa và thay thế tệp. Bạn có thể cũng làm tốt để có hành động được gọi bằng cách tìm kiểm tra xem còn đủ dung lượng trống trước khi di chuyển liên kết sym không.

Một giải pháp khác có thể là gắn kết hệ thống tệp được đề cập thông qua một cái gì đó ẩn các liên kết sym (như samba), sau đó chỉ cần sao chép mọi thứ ra khỏi đó. Nhưng trong nhiều trường hợp, một cái gì đó như thế sẽ giới thiệu các vấn đề khác.

Một câu trả lời trực tiếp hơn cho câu hỏi của bạn có lẽ là "có".

Chỉnh sửa: Theo yêu cầu để biết thêm thông tin cụ thể. Theo trang man để tìm , lệnh này sẽ liệt kê tất cả các tệp liên kết sym vào độ sâu của 2 thư mục, từ /:

find / -maxdepth 2 -type l -print

( điều này đã được tìm thấy ở đây )

Để tìm thấy để thực hiện một cái gì đó trên việc tìm kiếm nó:

find / -maxdepth 2 -type l -exec ./ReplaceSymLink.sh {} \;

Tôi tin rằng sẽ gọi một số tập lệnh tôi vừa tạo và chuyển vào tên tệp bạn vừa tìm thấy. Ngoài ra, bạn có thể nắm bắt kết quả tìm kiếm vào tệp (sử dụng "find [blah]> symlinks.data", v.v.) sau đó chuyển tệp đó vào tập lệnh bạn đã viết để xử lý sao chép trên bản gốc một cách duyên dáng.


? Một chút chung chung - bạn có thể xây dựng?
Linker3000

2
Cú pháp là-exec ./ReplaceSymLink.sh {} \;
grawity

Đây là để tìm các mục và một mục được đánh dấu là câu trả lời được sử dụng để thay thế các liên kết!
Marty Trenouth

3

Đây là oneliner tôi đã sử dụng: giả sử tất cả các tệp cục bộ là liên kết đến một tệp khác trong "nguồn". Bạn có thể tinh chỉnh lựa chọn tệp với các mẫu hoặc "tìm". Xin vui lòng, hiểu trước khi sử dụng.

cho f trong *; làm cp - nguồn đích-$ / $ f $ f; làm xong

Hi vọng điêu nay co ich


làm thế nào về việc sử dụng readlink: cho f trong *; làm cp ---- remove-Destination "$ (readlink $ f)" "$ f"; xong
Diego

Vâng, đó là một ý tưởng tốt, nhưng bạn mất một số kiểm soát đối với hoạt động. Một giới hạn của giải pháp của tôi là nó không hoạt động đối với các tệp có khoảng trống ở giữa hoặc cho các danh sách rất dài. Có lẽ giải pháp cuối cùng là kết hợp 'find --exec' ở trên với 'loại bỏ đích'. Có ai muốn thử không?
MastroGeppetto

khoảng trống ở giữa nên được giảm thiểu bằng cách đặt "$ f" trong doublequote. Đây là cách tôi sử dụng nó với "find & xargs" thay vì "for loop": find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --remove-Destination $ (readlink "{ } ")" {} "'Tôi đã đăng nó dưới dạng câu trả lời riêng cho khả năng hiển thị. superuser.com/a/1329543/499386
Diego

2
find . -type l -exec cp --dereference --recursive '{}' '{}'.dereferenced \;

Sẽ tạo một bản sao của từng tệp / thư mục được liên kết trong <filename>.dereferencedđó, an toàn hơn (nếu không thuận tiện) hơn là chỉ thay thế chúng trực tiếp. Di chuyển dữ liệu đã sao chép sang tên tệp của liên kết tượng trưng được để lại như một bài tập cho người đọc.


2

Sử dụng một số ý tưởng trước đó, lệnh sau sẽ thay thế đệ quy mọi liên kết tượng trưng bằng một bản sao của bản gốc:

find . -type l -exec bash -c "echo 'Replacing {} ...';  cp -LR '{}' '{}'.dereferenced;  rm '{}';  mv '{}'.dereferenced '{}'" \;


1

Có rất nhiều câu trả lời hay nhưng tôi vì bạn đang tìm kiếm thứ gì đó dễ dàng

for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done

Một chút cải tiến sẽ giúp tìm các liên kết tượng trưng: cho lnk trong `find. -type l`; làm src = $ (đường dẫn đọc $ lnk) && rm $ lnk && mv $ src $ lnk; thực hiện (không được kiểm tra với hệ thống phân cấp, hãy cẩn thận với backticks)
Roman Susi

1

Tôi gặp vấn đề tương tự với các liên kết sao chép gwenview khi bạn thường mong đợi nó theo liên kết và sao chép tệp.

Những gì tôi đã làm để 'dọn dẹp' thư mục bằng cách theo tất cả các liên kết và sao chép tất cả các tệp được trỏ vào thư mục, là tạo một thư mục cào, chạy ví dụ

"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./" 

Điều này quá nguy hiểm để đưa vào một kịch bản vì không có kiểm tra nhưng nó đã khắc phục vấn đề của tôi.



0

Tôi đã làm một phiên bản một dòng, vì khách sạn web của tôi không cho phép bash-scripts và nó hoạt động tốt với tôi:

before:
> find . -type l | wc -l
358

> for link in `find . -type l` ; do echo "$link : "; ls -al $link ; cp $link notalink; unlink $link; mv notalink $link ; ls -al $link; done
...

after:
> find . -type l | wc -l
0
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.