Tôi có thể sử dụng lệnh idempotent nào để tạo symlink trỏ đến một thư mục?


16

Tôi muốn đặt một lệnh vào tập lệnh shell sẽ tạo ra một liên kết tượng trưng đến thư mục, nhưng tập lệnh này có thể được chạy đi chạy lại, vì vậy trong các lần gọi tiếp theo, lệnh không nên thay đổi bất cứ điều gì.

Đây là cấu trúc thư mục:

% tree /tmp/test_symlink 
/tmp/test_symlink
├── foo
└── repo
    └── resources
        └── snippets
            ├── php.snippets
            ├── sh.snippets
            ├── snippets.snippets
            ├── sql.snippets
            └── vim.snippets

Tôi muốn tạo một liên kết tượng trưng trong foo/các đoạn được gọi là đoạn trỏ đến thư mục /tmp/test_symlink/repo/resources/snippets.
Vì vậy, tôi chạy:

% ln -sfv /tmp/test_symlink/repo/resources/snippets /tmp/test_symlink/foo/snippets
'/tmp/test_symlink/foo/snippets' -> '/tmp/test_symlink/repo/resources/snippets'

mà cho kết quả mong muốn.

% tree /tmp/test_symlink                                                          
/tmp/test_symlink
├── foo
   └── snippets -> /tmp/test_symlink/repo/resources/snippets
└── repo
    └── resources
        └── snippets
            ├── php.snippets
            ├── sh.snippets
            ├── snippets.snippets
            ├── sql.snippets
            └── vim.snippets

5 thư mục, 5 tập tin

Tuy nhiên, khi lệnh được chạy lại,

% ln -sfv /tmp/test_symlink/repo/resources/snippets /tmp/test_symlink/foo/snippets
'/tmp/test_symlink/foo/snippets/snippets' -> '/tmp/test_symlink/repo/resources/snippets'

nó tạo một symlink đến một thư mục, trong đó symlink luôn tồn tại sẽ đặt symlink bên trong thư mục thực

% tree /tmp/test_symlink                                                          
/tmp/test_symlink
├── foo
   └── snippets -> /tmp/test_symlink/repo/resources/snippets
└── repo
    └── resources
        └── snippets
            ├── php.snippets
            ├── sh.snippets
            ├── snippets -> /tmp/test_symlink/repo/resources/snippets
            ├── snippets.snippets
            ├── sql.snippets
            └── vim.snippets

Tại sao điều này xảy ra và làm thế nào tôi có thể sửa đổi lệnh để các lệnh tiếp theo sẽ không tạo ra hiệu ứng kỳ lạ này?

Câu trả lời:


16

Bạn nên sử dụng -Ttùy chọn này, nó lnluôn luôn coi tên liên kết là tên liên kết mong muốn, không bao giờ là một thư mục.

Nếu không có tùy chọn này, nếu bạn đưa ra lnmột tên liên kết tồn tại dưới dạng thư mục, nó sẽ tạo ra một liên kết mới đến mục tiêu bên trong thư mục đó.

Lưu ý rằng đó -Tlà một GNU-ism (ít nhất, nó không có trong POSIX), nhưng bạn cũng đang sử dụng -vmột GNU-ism nên tôi tưởng tượng đó không phải là vấn đề.

Ngoài ra, bạn chỉ có thể chỉ định thư mục mẹ là tên liên kết và liên kết sẽ luôn được tạo lại ở đó:

ln -sfv /tmp/test_symlink/repo/resources/snippets /tmp/test_symlink/foo/

Điều này hoạt động vì symlink của bạn có cùng tên với mục tiêu.


cảm ơn, vâng, các tùy chọn gnu không nhất thiết phải là di động, nhưng chúng có thể thực sự hữu ích - khi tính di động không phải là một yêu cầu. câu trả lời của bạn làm việc cho tôi. Từ trang đàn ông -n, --no-dereference treat LINK_NAME as a normal file if it is a symbolic link to a directory. -T, --no-target-directory treat LINK_NAME as a normal file alwaysBạn có nghĩ rằng tốt hơn là coi symlink là một tệp luôn không? Tôi có thể nghĩ rằng sẽ tốt hơn nếu hạn chế sử dụng các tùy chọn "đặc biệt" này?
the_velour_fog

Nếu bạn biết chúng khả dụng, không có lý do gì để tránh các tùy chọn dành riêng cho GNU (IMO). Bạn đã yêu cầu một lệnh idempotent, -Tlà cách bạn tạo ra lnidempotent. Có nhiều cách khác để có được kết quả tương tự nếu bạn thích, chẳng hạn như xóa liên kết và tạo lại liên kết hoặc nếu bạn biết foođã tồn tại, ln -sfv /tmp/test_symlink/repo/resources/snippets /tmp/test_symlink/foo/(thực sự đó có thể là một câu trả lời tốt hơn, tôi sẽ cập nhật).
Stephen Kitt

1
Thật tuyệt, vâng, trước đây tôi đã sử dụng các ifcâu lệnh để phát hiện sự hiện diện của symlink và bỏ qua lệnh nếu symlink tồn tại, nhưng các đoạn script cuối cùng bị lộn xộn và khó đọc, tôi sẽ tìm một thứ gì đó bình thường nhưng đơn giản, như mkdir -pkhông sử dụng thử nghiệm , không logic, chỉ cần một người lót tốt thôi :)
the_velour_fog

@Stephen Kitt: bạn đã đề cập đến việc sử dụng -T, nhưng tôi không thể tìm thấy nó trong đoạn mã câu trả lời của bạn. Tôi có hiểu lầm hay thiếu thứ gì không?
Guizmoo03

@ Guizmoo03 có lẽ bạn đã bỏ lỡ các chương trình Thay thế giới thiệu đoạn trích. Ba đoạn đầu giải thích -T, nhưng phần cuối câu trả lời của tôi trình bày một giải pháp khác không sử dụng -T.
Stephen Kitt

-1

Tốt nhất tôi có thể nói những gì đang xảy ra ở đây là trên đường chuyền thứ hai, lnlệnh này hoạt động như thế nào cp, hoặc mvlà nếu nó nhìn thấy một "thư mục" tại <Destination> thì nó sẽ đặt tệp vào bên trong, nếu không thì <Destination> không tồn tại, nó sẽ làm cho <đích>. (đó là những gì mà thủ thuật "slashdot" tránh được - tức là nó sẽ đảm bảo <Destination> tồn tại và là một thư mục).
Nhưng tôi có thể sai.

Trong cả hai trường hợp, điều này dường như làm việc

ln -sfv --no-dereference /tmp/test_symlink/repo/resources/snippets/ foo/snippets
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.