คำสั่ง idempotent ใดที่ฉันสามารถใช้เพื่อสร้าง symlink ให้ชี้ไปที่ไดเรกทอรี


16

ฉันต้องการใส่คำสั่งลงในเชลล์สคริปต์ซึ่งจะสร้าง symlink ไปยังไดเรกทอรี แต่สคริปต์นี้สามารถเรียกใช้ซ้ำแล้วซ้ำอีกดังนั้นในการเรียกใช้ครั้งต่อไปคำสั่งไม่ควรเปลี่ยนแปลงอะไร

นี่คือโครงสร้างไดเรกทอรี:

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

ผมต้องการสร้าง symlink ในที่เรียกว่าตัวอย่างที่ชี้ไปยังไดเรกทอรีfoo/ ดังนั้นฉันวิ่ง:/tmp/test_symlink/repo/resources/snippets

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

ซึ่งให้ผลลัพธ์ที่ต้องการ

% 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 ไดเรกทอรี 5 ไฟล์

อย่างไรก็ตามเมื่อคำสั่งรันอีกครั้ง

% 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'

มันสร้าง symlink ไปยังไดเรกทอรีที่มี symlink aleady อยู่ทำให้ symlink ภายในไดเรกทอรีจริง

% 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

เหตุใดสิ่งนี้จึงเกิดขึ้นและฉันจะแก้ไขคำสั่งเพื่อที่การเรียกใช้ในภายหลังจะไม่สร้างผลแปลก ๆ นี้ได้อย่างไร

คำตอบ:


16

คุณควรใช้-Tตัวเลือกสำหรับสิ่งนี้มันบอกlnให้ปฏิบัติกับชื่อลิงค์เป็นชื่อลิงค์ที่ต้องการไม่เคยเป็นไดเรกทอรี

หากไม่มีตัวเลือกนี้หากคุณให้lnชื่อลิงก์ที่มีอยู่ในไดเรกทอรีมันจะสร้างลิงค์ใหม่ไปยังเป้าหมายภายในไดเรกทอรีนั้น

โปรดทราบว่านั่น-Tคือ GNU-ism (อย่างน้อยก็ไม่ใช่ใน POSIX) แต่คุณกำลังใช้งานอยู่-vซึ่งเป็น GNU-ism ด้วยดังนั้นฉันคิดว่านั่นไม่ใช่ปัญหา

หรือคุณเพียงแค่ระบุไดเรกทอรีหลักเป็นชื่อลิงก์และลิงก์จะถูกสร้างขึ้นใหม่ที่นั่น:

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

สิ่งนี้ทำงานได้เพราะ symlink ของคุณมีชื่อเหมือนกับเป้าหมาย


ขอบคุณใช่ตัวเลือก gnu นั้นไม่จำเป็นต้องพกพา แต่มีประโยชน์จริงๆ - เมื่อการพกพาไม่ใช่ข้อกำหนด คำตอบของคุณใช้ได้สำหรับฉัน -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 alwaysคุณคิดว่ามันจะดีกว่าหรือไม่ที่จะใช้ symlink เป็นไฟล์เสมอ ฉันคิดว่าคงเป็นการดีกว่าถ้าจะ จำกัด การใช้ตัวเลือก "พิเศษ" เหล่านี้
the_velour_fog

หากคุณรู้ว่ามีให้บริการก็ไม่มีเหตุผลที่จะหลีกเลี่ยงตัวเลือกเฉพาะของ GNU (IMO) คุณถามหาคำสั่ง idempotent -Tเป็นวิธีที่คุณสร้างlnidempotent มีวิธีอื่นในการรับผลลัพธ์เดียวกันหากคุณต้องการเช่นการลบลิงก์และสร้างใหม่อีกครั้งหรือถ้าคุณรู้ว่าfooมีอยู่แล้วln -sfv /tmp/test_symlink/repo/resources/snippets /tmp/test_symlink/foo/(จริง ๆ แล้วอาจเป็นคำตอบที่ดีกว่าโดยสิ้นเชิงฉันจะอัปเดต)
Stephen Kitt

1
เย็นใช่ฉันเคยใช้ifงบในการตรวจสอบสถานะของ symlink และข้ามคำสั่งถ้า symlink มีอยู่ แต่สคริปต์ท้ายรับรกและยากที่จะอ่านผมจะหาสิ่ง idempotent แต่ง่ายเช่นการใช้mkdir -pไม่มีการทดสอบ ไม่มีตรรกะเพียงแค่หนึ่ง liners ดี :)
the_velour_fog

@Stephen Kitt: คุณพูดถึงการใช้ -T แต่ฉันหามันไม่เจอใน code code ของคำตอบของคุณ ฉันเข้าใจผิดหรือขาดอะไรไปหรือเปล่า?
Guizmoo03

@ Guizmoo03 คุณอาจพลาด "อีกทางหนึ่ง" ซึ่งแนะนำตัวอย่างข้อมูล สามย่อหน้าแรกอธิบายแต่ในตอนท้ายของคำตอบของฉันนำเสนอวิธีการแก้ปัญหาอื่นที่ไม่ได้ใช้-T -T
สตีเฟ่น Kitt

-1

ดีที่สุดที่ฉันสามารถบอกได้ว่าสิ่งที่เกิดขึ้นที่นี่คือในครั้งที่สองผ่านlnคำสั่งพฤติกรรมเช่นcpหรือmvซึ่งก็คือถ้ามันเห็น "ไดเรกทอรี" ที่ <destination> มันจะวางไฟล์ไว้ข้างในอื่นถ้า <destination> ไม่ มีอยู่มันจะทำให้ <destination> (ซึ่งเป็นสิ่งที่ "เคล็ดลับ" slashdot "หลีกเลี่ยง - เช่นมันจะทำให้แน่ใจว่า <destination> มีอยู่และเป็นไดเรกทอรี)
แต่ฉันอาจจะผิด

ในทั้งสองกรณีนี้ดูเหมือนว่าจะทำงาน

ln -sfv --no-dereference /tmp/test_symlink/repo/resources/snippets/ foo/snippets
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.