แทนที่ลิงก์สัญลักษณ์ด้วยไฟล์


31

มีวิธีง่าย ๆ ในการแทนที่ลิงก์สัญลักษณ์ทั้งหมดด้วยไฟล์ที่ลิงก์ไปหรือไม่?


3
คุณพยายามแก้ไขปัญหาอะไร
Daniel Beck

3
ฉันมีลิงค์สัญลักษณ์มากมายไปยังไดรฟ์อื่น ฉันต้องการย้ายไฟล์ทั้งหมดออกจากไดรฟ์ที่อ้างอิงที่อื่นเพื่อให้สามารถลบออกได้
Marty Trenouth

คำตอบ:


14

สำหรับคำจำกัดความของ "ง่าย":

#!/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

เรียกใช้สคริปต์นี้ด้วยชื่อลิงก์เป็นอาร์กิวเมนต์เช่นผ่าน find . -type l -exec /path/tos/script {} +


2
ขอบคุณสำหรับการแก้ไขอานนท์ แต่สคริปต์ไม่ชื่อไฟล์การจัดการที่มีช่องว่างเพียงแค่ปรับโดยการอ้างตัวแปรในสถานที่ที่จำเป็นทั้งหมด เปลี่ยน"$var"ไป"${var}"เป็น noop ในการดวลจุดโทษ / ทุบตี ฉันลบหนึ่ง bashism ( [[) ส่วนที่เหลือเข้ากันได้กับ POSIX sh
grawity

วิธีการที่แข็งแกร่งยิ่งขึ้นสำหรับการจัดการความล้มเหลวของ symlink คือการไปcpยังไฟล์ชั่วคราวในไดเรกทอรีเดียวกันจากนั้นmv -fไฟล์ชั่วคราวนั้นจะเป็นต้นฉบับ นี้ควรป้องกันปัญหาเช่นคนที่ถือลงCtrl-Cหรือระบบแฟ้มเติมขึ้นระหว่างrmและcpคำสั่ง (จึงป้องกันได้ใหม่lnจากการทำงาน) ชื่อไฟล์ชั่วคราวนั้นง่ายls -aต่อการทำความสะอาดในภายหลังหากจำเป็น
Mr Fooz

ตามบันทึกข้างฉันอย่างจริงจังจำไม่ได้ว่าทำไมผมไม่ได้เพียงแค่ใช้abstarget=$(readlink -f "$link")แทนกรณีบล็อก แต่มันอาจจะเป็นเหตุผลในการพกพา
grawity

17

อาจจะง่ายกว่าเพียงแค่ใช้ tar เพื่อคัดลอกข้อมูลไปยังไดเรกทอรีใหม่

-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.

คุณสามารถใช้สิ่งนี้

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
ฉันรักทางออกของคุณ แต่ฉันไม่เข้าใจส่วนสุดท้ายของข้อความของคุณ สำหรับฉันคุณควรทำ:tar -hcf - sourcedir | tar -xf - -C newdir
Seb DA ROCHA

1
ตกลงคำตอบนี้จะต้องปรับปรุงตามความคิดเห็น
astabada

1
cp -Lเป็นวิธีแก้ปัญหาที่ง่ายกว่า
plesiv

@plesiv จริงและสอดคล้องกับ posix แต่cpการใช้งานไม่ได้ทั้งหมดจะคัดลอกไดเรกทอรี
Wyatt8740

16

หากฉันเข้าใจคุณอย่างถูกต้อง-Lค่าสถานะของcpคำสั่งควรทำสิ่งที่คุณต้องการ

เพียงคัดลอกลิงก์ทั้งหมดและมันจะแทนที่ด้วยไฟล์ที่พวกเขาชี้ไปที่


4
ขอบคุณ - เกือบสิ่งที่ฉันต้องการ: ฉันต้องทำสิ่งที่ชอบ: cp -L files tmp/ && rm files && cp tmp/files . ถ้าคุณชี้แจงคุณอาจจะช่วยผู้คนมากขึ้น ...
ปราชญ์

5

"ง่าย" จะเป็นหน้าที่ของคุณ

ฉันอาจจะเขียนสคริปต์ที่ใช้ยูทิลิตีบรรทัดคำสั่ง "find" เพื่อค้นหาไฟล์ที่มีสัญลักษณ์เชื่อมโยงจากนั้นเรียก rm และ cp เพื่อลบและแทนที่ไฟล์ คุณน่าจะทำได้ดีหากมีการดำเนินการที่เรียกว่าโดยการตรวจสอบการค้นหาว่ามีพื้นที่ว่างเหลือพอก่อนที่จะย้ายลิงก์ sym ด้วย

วิธีแก้ไขปัญหาอื่นอาจเป็นการเมานต์ระบบไฟล์ที่เป็นปัญหาผ่านสิ่งที่ซ่อนลิงก์ sym (เช่น samba) จากนั้นคัดลอกทุกอย่างออก แต่ในหลายกรณีบางอย่างเช่นนั้นจะแนะนำปัญหาอื่น ๆ

คำตอบที่ตรงกับคำถามของคุณน่าจะเป็น "ใช่"

แก้ไข: ตามคำขอสำหรับข้อมูลที่เฉพาะเจาะจงมากขึ้น ตามหน้า man for findคำสั่งนี้จะแสดงรายการไฟล์ sym ลิงก์ทั้งหมดในความลึก 2 ไดเรกทอรีจาก /:

find / -maxdepth 2 -type l -print

( พบที่นี่ )

หากต้องการค้นหาเพื่อดำเนินการบางอย่างกับการค้นหา:

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

ฉันเชื่อว่าจะเรียกสคริปต์ที่ฉันเพิ่งสร้างขึ้นและส่งชื่อไฟล์ที่คุณเพิ่งพบ หรือคุณสามารถจับค้นหาผลลัพธ์ไปยังไฟล์ (ใช้ "find [blah]> symlinks.data" ฯลฯ ) จากนั้นส่งไฟล์นั้นไปยังสคริปต์ที่คุณเขียนขึ้นเพื่อจัดการกับการคัดลอกต้นฉบับอย่างงดงาม


? ทั่วไปเล็กน้อย - คุณช่วยอธิบายได้ไหม?
Linker3000

2
ไวยากรณ์คือ-exec ./ReplaceSymLink.sh {} \;
grawity

นี่คือการไปหารายการและรายการที่ทำเครื่องหมายว่าเป็นคำตอบที่ใช้ในการแทนที่ลิงก์!
Marty Trenouth

3

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

สำหรับ f ใน *; ทำซีพี - ลบแหล่งที่มาปลายทาง / $ f $ f; เสร็จแล้ว

หวังว่านี่จะช่วยได้


วิธีใช้ readlink: สำหรับ f ใน *; ทำ cp ---- ลบปลายทาง "$ (readlink $ f)" "$ f"; เสร็จแล้ว
Diego

ใช่เป็นความคิดที่ดี แต่คุณไม่สามารถควบคุมการปฏิบัติงานได้ ข้อ จำกัด อย่างหนึ่งของโซลูชันของฉันคือมันใช้ไม่ได้กับไฟล์ที่มีช่องว่างตรงกลางหรือสำหรับรายการที่ยาวมาก อาจเป็นทางออกสุดท้ายคือการรวบรวม 'find --exec' ด้านบนด้วย 'remove destination' ใครอยากลองบ้าง
MastroGeppetto

ช่องว่างตรงกลางควรจะลดลงด้วยการใส่ "$ f" ใน doublequotes นี่คือวิธีที่ฉันใช้กับ "find & xargs" แทน "for loop": find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp - ลบปลายทาง $ (readlink "{ } ")" {} "'ฉันโพสต์ไว้เป็นคำตอบแยกต่างหากสำหรับการเปิดเผย superuser.com/a/1329543/499386
Diego

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

จะทำสำเนาของไฟล์ / โฟลเดอร์ symlinked แต่ละไฟล์<filename>.dereferencedซึ่งปลอดภัยกว่า (ถ้าสะดวกน้อยกว่า) แทนที่จะทำการแทนที่โดยตรง การย้ายข้อมูลที่คัดลอกไปยังชื่อไฟล์ของ symlink นั้นจะเป็นแบบฝึกหัดสำหรับผู้อ่าน


2

การใช้แนวคิดก่อนหน้านี้บางคำสั่งต่อไปนี้จะแทนที่ symlink ทุกครั้งด้วยสำเนาของต้นฉบับ:

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


1

มีคำตอบที่ดีมากมาย แต่ฉันเนื่องจากคุณกำลังมองหาบางสิ่งที่ง่าย

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

การปรับปรุงเล็กน้อยจะช่วยในการค้นหาลิงก์สัญลักษณ์: สำหรับ lnk ใน `find ประเภท l`; ทำ src = $ (readlink $ lnk) && rm $ lnk && mv $ src $ lnk; เสร็จแล้ว (ไม่ได้ทดสอบกับลำดับชั้น แต่ระวัง backticks)
Roman Susi

1

ฉันมีปัญหาเดียวกันกับการคัดลอกลิงก์ gwenview เมื่อคุณคาดหวังว่ามันจะตามลิงค์และคัดลอกไฟล์

สิ่งที่ฉันทำเพื่อ 'ทำความสะอาด' ไดเรกทอรีโดยทำตามลิงค์ทั้งหมดและคัดลอกไฟล์ชี้ไปยังไดเรกทอรีทั้งหมดได้สร้างไดเรกทอรีรอยขีดข่วนเรียกใช้เช่น

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

มันอันตรายเกินไปที่จะใส่สคริปต์เนื่องจากไม่มีการตรวจสอบ แต่แก้ไขปัญหาของฉันได้



0

ฉันทำรุ่นหนึ่งบรรทัดเนื่องจากเว็บโรงแรมของฉันไม่อนุญาตให้ใช้สคริปต์ทุบตีและทำงานได้ดีสำหรับฉัน:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.