วิธีคัดลอกโครงสร้างโฟลเดอร์และสร้างลิงก์สัญลักษณ์ไปยังไฟล์ได้อย่างไร


21

ฉันมีโฟลเดอร์ SOURCE ที่มีโฟลเดอร์ย่อยหลายโฟลเดอร์โดยแต่ละไฟล์มีไฟล์ของตัวเอง

ฉันต้องการคัดลอกโฟลเดอร์นี้ในโฟลเดอร์ใหม่คัดลอกที่ฉันต้องการคัดลอกโครงสร้างไดเรกทอรี แต่เก็บไฟล์เป็นลิงก์สัญลักษณ์ไปยังไฟล์ต้นฉบับใน SOURCE และโฟลเดอร์ย่อย


1
ดูเพิ่มเติมstackoverflow.com/q/1240636/905686
user905686

GNU Stowค่อนข้างเป็นแบบนี้
Kusalananda

คำตอบ:


27

นี่คือวิธีการแก้ปัญหาบน Linux และ Cygwin ที่ไม่ใช่แบบฝังตัว:

cp -as SOURCE/ COPY

โปรดทราบว่าแหล่งที่มาจะต้องเป็นเส้นทางที่แน่นอนและมีเครื่องหมายทับ หากคุณต้องการให้เส้นทางสัมพัทธ์คุณสามารถใช้

cp -as "$(pwd)/SOURCE/" COPY

ทำงานได้สมบูรณ์แบบขอบคุณ เพียงแค่ทราบ .. ต้องมีแหล่งที่มาพร้อมกับเส้นทางแบบเต็ม (สามารถคัดลอกได้ในเงื่อนไขที่เกี่ยวข้องหากต้องการ)
Antonello

จะทำให้มันทำงานได้อย่างไรถ้าไดเรกทอรีต้นฉบับจะได้รับการอัปเดตตลอดเวลาด้วยโฟลเดอร์ใหม่และไฟล์ใหม่ภายใน symlink จะถูกสร้างขึ้นโดยอัตโนมัติในไดเรกทอรีปลายทางในโครงสร้างโฟลเดอร์ที่ถูกต้องหรือไม่
SexyBeast

@AttitudeMonger ไม่คำสั่งเช่น cp เพิ่งสร้างลิงค์ครั้งเดียว (ดังที่คุณเห็นจากผลลัพธ์) หากต้องการอัปเดตปลายทางโดยอัตโนมัติคุณจะต้องตรวจสอบไดเรกทอรีต้นทางเพื่อดูการเปลี่ยนแปลง
user905686

สามารถทำสิ่งนี้เพื่อสร้างลิงก์ที่เกี่ยวข้องได้หรือไม่
ctrl-alt-delor

@ Richard ถ้าSOURCE เป็นเส้นทางญาติแล้วฉันคิดอย่างนั้น ลองใช้และหากวิธีนี้ใช้ไม่ได้ฉันขอแนะนำให้คุณอาจต้องการถามคำถามใหม่ อ้างอิงอันนี้ทุกวิถีทาง
roaima

6

มียูทิลิตี้มาตรฐานอย่างน้อย 2 ตัวในการสร้างแผนผังไดเรกทอรีเงาของต้นไม้ที่มีอยู่ดังนั้นไม่จำเป็นต้องเขียนโค้ดที่นี่

ก่อนอื่นlndir(1)มาจากxutils-devแพ็คเกจ มันใช้ symlink กับไฟล์ จากหน้าคน:

NAME
   lndir  -  create a shadow directory of symbolic links to another
             directory tree
SYNOPSIS
   lndir [ -silent ] [ -ignorelinks ] [ -withrevinfo ] fromdir [ todir ]

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

cp -al /src/dir /dest/dir    # hard-links to leaf-files
cp -as /src/dir /dest/dir    # symlinks to leaf-files

หากคุณไม่สนใจเกี่ยวกับการรักษาคุณลักษณะทั้งหมด (ความเป็นเจ้าของ / สิทธิ์ครั้ง) ให้แทนที่aตัวเลือก (เทียบเท่า-dr --preserve=all) ด้วยr(เรียกซ้ำเท่านั้น):

cp -rl /src/dir /dest/dir    # hard-links to leaf-files
cp -rs /src/dir /dest/dir    # symlinks to leaf-files

lndirมีให้ใช้งานเป็นสคริปต์เชลล์ที่นี่ในกรณีที่ไม่ได้ติดตั้ง: opensource.apple.com/source/X11/X11-0.46.4/lndir.sh?txt
Lenar Hoyt

2

คุณสามารถลองใช้คำสั่ง find สองสามแบบดังนี้:

mkdir FULL-PATH-TO-COPY
cd SOURCE
find . \( ! -regex '\.' \) -type d -exec mkdir FULL-PATH-TO-COPY/{} \;
find * -type f -exec ln -s `pwd`/{} FULL-PATH-TO-COPY/{} \;

1

สิ่งนี้จะทำในสิ่งที่คุณต้องการ

#!/bin/bash
#
SOURCE="$1" COPY="$2"
cd "$SOURCE"
find . |
    sed 's!^\./!!' |
    while IFS= read ITEM
    do
        test -d "$ITEM" && { mkdir -p "$COPY/$ITEM"; continue; }
        BASE="${FILE%\/*}"
        ( cd "$COPY/$BASE" && ln -s "$SOURCE/$ITEM" )
    done

ไดเรกทอรีถูกสร้างขึ้นในแผนผัง COPY เป้าหมาย ทุกสิ่งทุกอย่างจะเชื่อมโยงกลับไปยังเส้นทางที่สมบูรณ์ภายในทรี SOURCE ตรวจสอบให้แน่ใจว่าทั้งแหล่งที่มาและสำเนาถูกระบุเป็นพา ธ สัมบูรณ์ (เริ่มต้นด้วย/)

หากคุณมีต้นไม้ขนาดใหญ่ที่จะคัดลอกและคุณต้องการรายงานความคืบหน้าต่อไดเรกทอรีคุณสามารถเพิ่มecho "$ITEM" >&2;ก่อนmkdirคำสั่ง

(ฉันดูcpแล้วcpioแต่ดูเหมือนจะไม่มีตัวเลือกสำหรับการลิงก์ไปยังแหล่งที่มาพร้อมกับลิงก์สัญลักษณ์)


1
ความคิดเห็น "line 9 test" อาจเกี่ยวข้องกับ ksh บน AIX ต้องการเซมิโคลอนเพื่อปิดรายการวงเล็บปีกกา:{ mkdir -p "$COPY/$ITEM"; continue; }
Jeff Schaller

@JeffSchaller ขอบคุณ ฉันไม่ได้เขียนkshสคริปต์ ... แต่ดูเหมือนว่ามันก็จำเป็นbashเช่นกัน แก้ไข
roaima

0

หากไม่มี dirs ที่ว่างเปล่าใน SOURCE ซึ่งจำเป็นต้องคัดลอก

find /full/path/to/SOURCE -type f -exec cp -t COPY --parents -s {} +
mv COPY/full/path/to/SOURCE COPY
rm -r COPY/full

1
เนื่องจากคุณสมมติว่า GNU cpอยู่แล้วทำไมcp -asล่ะ
Gilles 'หยุดความชั่วร้าย'

0

ฉันจะเริ่มต้นด้วยการทำลาย perl:

#!/usr/bin/perl

use strict;
use warnings;
use File::Find;

my $src_dir = "/full_path/to/dir";
my $tgt_dir = "/path/to/new/location";

sub link_or_mkdir {

    #current file is directory
    if (-d) {
        #extract the path
        my $newpath = $File::Find::dir;
        #change the path so 'old' and 'new' are swapped
        $newpath =~ s,^$src_dir,$tgt_dir,g;
        #print the command to make a new dir (doesn't actually do it)
        print "mkdir -p $newpath\n";
    }
    if (-f) {
        my $new_file = $File::Find::name;
        #change the path so 'old' and 'new' are swapped
        $new_file =~ s,^$src_dir,$tgt_dir,g;
        #print the symlink command
        print "ln -s $File::Find::name $new_file\n";
    }
}

find( \&link_or_mkdir, $tgt_dir );

File::Findเป็นโมดูลที่มีประโยชน์ที่อนุญาตให้คุณเรียกใช้รูทีนย่อยเฉพาะบนไฟล์ใด ๆ ภายในแผนผังไดเร็กทอรี ในกรณีนี้ส่วนย่อยจะตรวจสอบว่าเป็นไดเรกทอรีmkdirหรือไม่และเป็นไฟล์หรือไม่ซึ่งในกรณีนี้ symlink


-1

ดูเหมือนว่าคุณกำลังมองหาบางสิ่งบางอย่างเช่นเครื่องมือrsnapshot; มันสร้างสำเนาของไดเรกทอรีที่กำหนดเองและใช้ฮาร์ดลิงก์เมื่อทำได้ (ดูที่หน้า man page เพื่อดูว่าเหมาะสมหรือไม่)


ไม่คำถามขอให้ symlink อย่างชัดเจนและ rsnapshot ใช้ hardlinks (เนื่องจากเป็นเครื่องมือสำรองและไฟล์ควรถูกเก็บไว้แม้ว่าจะถูกลบออกจากไดเรกทอรีต้นทาง) ก็ตาม
user905686
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.