จะเขียนทับไฟล์เป้าหมายด้วย mv ได้อย่างไร?


154

ฉันมีไฟล์และ dirs มากมายในไดเรกทอรีย่อยฉันต้องการย้ายไปยังไดเรกทอรีหลัก มีไฟล์และไดเร็กตอรี่บางส่วนอยู่ในไดเรกทอรีเป้าหมายซึ่งจำเป็นต้องเขียนทับ ไฟล์ที่มีอยู่ในเป้าหมายเท่านั้นควรไม่ถูกแตะต้อง ฉันสามารถบังคับmvให้ทำเช่นนั้นได้หรือไม่? มัน ( mv * ..) บ่น

mv: cannot move `xyz' to `../xyz': Directory not empty

ฉันพลาดอะไรไป


3
คุณเคยลองmv -fไหม
sakisk

ฉันสงสัยว่าทำไมmv -fคำตอบที่ไม่ถูกต้อง
Pedro Lobito

@PedroLobito: เพราะมันไม่ทำงาน? - เขียนทับไฟล์เท่านั้น แต่จะไม่ทำงานหากคุณย้ายไดเรกทอรีย่อยที่มีอยู่ในปลายทางและไม่ว่างเปล่า
EricSchaefer

คำตอบ:


117

คุณจะต้องคัดลอกไปยังปลายทางแล้วลบแหล่งที่มาโดยใช้คำสั่งตามมาด้วยcp -r * ..rm -rf *

ผมไม่คิดว่าคุณสามารถ "ผสาน" mvไดเรกทอรีใช้


4
นั่นคือสิ่งที่ฉันไม่ต้องการทำเพราะจะใช้เวลานาน ... ขอบคุณ
EricSchaefer

12
น่าmvจะเร็วกว่าเพราะคุณอยู่ในระบบไฟล์เดียวกัน ถ้าหากคุณใช้cp -lสร้างฮาร์ลิงค์แทนที่จะย้ายไฟล์จริงๆล่ะ
mattdm

6
คุณควรใช้cp -aแทนcp -rเพื่อรักษาคุณสมบัติของไฟล์ (การประทับเวลาการอนุญาต ฯลฯ )
dotancohen

2
สำหรับผู้ที่มาถึงที่นี่ช้าผ่าน google คำตอบด้านล่างโดย @palswim เลียนแบบพฤติกรรมของ mv โดยการสร้างฮาร์ดลิงก์ใหม่ไปยังข้อมูลแล้วลบลิงก์เก่า คำตอบสั้นcp -rl source destination && rm -r source
William Everett

72

rsyncอาจเป็นตัวเลือกที่ดีกว่าที่นี่ rsync -a subdir/ ./มันเป็นธรรมดาที่

แผนภูมิการทดสอบของฉันในfilename: contentsรูปแบบ:

./file1:root
./file2:root
./dir/file3:dir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

วิ่งrsync:

$ rsync -a -v subdir/ ./
sending incremental file list
./
file1
dir/
dir/file3

ให้:

./file1:subdir
./file2:root
./dir/file3:subdir
./dir/file4:dir
./subdir/dir/file3:subdir
./subdir/file1:subdir

จากนั้นเพื่อเลียนแบบmvคุณอาจต้องการลบไดเรกทอรีแหล่งที่มา:

$ rm -r subdir/

ให้:

./file1:subdir
./file2:parent
./dir/file3:subdir
./dir/file4:dir

หากสิ่งนี้ผิดคุณช่วยยกตัวอย่างที่คล้ายกัน (เช่นการใช้แผนภูมิการทดสอบของฉันจากด้านบนสุดของคำตอบนี้) กับผลลัพธ์ที่ต้องการได้หรือไม่?


1
สำเนา rsync คำถามนี้เกี่ยวกับการเคลื่อนย้าย
Gilles

1
@Gilles: ขอบคุณ ฉันเพิ่มในตอนท้ายที่จะทำให้มันเป็นเช่นเดียวกับrm -r mv
Mikel

3
คัดลอกแล้วลบไม่เท่ากับ mv เมื่อแหล่งที่มาและปลายทางอยู่ในระบบไฟล์เดียวกัน mvคืออะตอมมิกรักษาหมายเลขไอโหนด (ดังนั้นไฟล์จะยังคงเปิดอยู่) และไม่ต้องใช้เวลาและพื้นที่ในการทำสำเนา
Gilles

5
@Gilles: ฉันตระหนักดีว่า cp -r; rm -rแต่ขณะนี้คำตอบที่เป็นผู้นำ ฉันคิดว่าในแง่rsyncนี้ก็คุ้มค่าที่จะพูดถึงเช่นกัน
มิเคล

ฉันทำไปแล้วด้วย cp / rm (มันเป็นเรื่องเร่งด่วน) ใช้เวลานานจริงๆ สคริปต์ของ Gilles น่าจะเร็วกว่านี้เยอะ แต่เขาก็สายเกินไป
EricSchaefer

47

rsyncสามารถลบซอร์สหลังจากคัดลอกด้วย--remove-source-filesพารามิเตอร์ นี่ควรเป็นวิธีที่สะดวกในการทำสิ่งที่คุณต้องการ

จากrsync man page:

        --remove-source-files   sender removes synchronized files (non-dir)

นี่เป็นคำตอบที่ดีที่สุดจริงๆ ฉันใช้ไม่ได้cp -r; rmเพราะขาดพื้นที่ว่าง แทนที่จะrsync --remove-source-filesลดขนาดพื้นที่ดิสก์ที่ใช้ทั้งสองให้หลีกเลี่ยงการคัดลอกไฟล์เดียวกันที่แน่นอน
guaka

20

คุณสามารถทำได้ด้วยcpและrmโดยไม่ต้องคัดลอกข้อมูลจำนวนมหาศาลที่คุณพยายามหลีกเลี่ยงการถ่ายโอน @mattdm พูดถึงสิ่งนี้ในความคิดเห็นของเขาและคำตอบสำหรับคำถามอื่นมีการอภิปรายที่สมบูรณ์มากขึ้นเกี่ยวกับตัวเลือกต่างๆ

cp -rlf source destination
rm -r source

โดยพื้นฐานแล้ว-lตัวเลือกสำหรับcpคำสั่งจะสร้างฮาร์ดลิงก์ไปยังไฟล์แทนที่จะคัดลอกข้อมูลไปยังไฟล์ใหม่


1
ฉันรู้ว่าOP เสร็จงานของเขาซึ่งแจ้งคำถาม แต่หวังว่าคำตอบนี้จะช่วยทุกคนที่มีปัญหานี้ในอนาคต
palswim

นี่เป็นคำตอบที่พวกเขาต้องการจริงๆ ฉันเพิ่งทำสิ่งนี้กับไฟล์อีเมลไซรัสเล็ก ๆ 60GB และใช้เวลาเพียง 21 วินาที
ลาบราดอร์

นี่เป็นเส้นทางที่ฉันใช้ไป - ฉันเพิ่งเปลี่ยนเป็นcp -al source destinationรักษาข้อมูลเจ้าของและการอนุญาต
piit79

ฉันคิดว่าจริง ๆ แล้วทำในสิ่งที่ OP ขอให้คุณต้องเพิ่มตัวเลือก -f มิฉะนั้นจะไม่เขียนทับหากไฟล์มีอยู่ คุณช่วยยืนยันได้หรือว่าฉันกำลังทำอะไรผิดพลาด?
das Keks

@dasKeks: ที่จริงแล้วcpเขียนทับโดยค่าเริ่มต้น -fตัวเลือกที่พยายามที่จะลบไฟล์ (ในrm) ก่อนที่จะพยายามที่จะคัดลอกใหม่ซึ่งสามารถช่วยถ้ากระบวนการไม่สามารถเปิดไฟล์สำหรับการเขียนแม้บางคนจะชอบที่จะเห็นว่ามีข้อผิดพลาดแทน ฉันไม่รู้ว่ามันมีความสำคัญกับ OP หรือไม่ แต่ฉันเพิ่มการ-fตั้งค่าสถานะลงในคำตอบของฉัน
palswim

8

นี่คือสคริปต์ที่จะย้ายไฟล์จากใต้ไปยังเส้นทางที่สอดคล้องกันภายใต้/path/to/source/root/path/to/destination/root

  • หากมีไดเรกทอรีอยู่ทั้งต้นทางและปลายทางเนื้อหาจะถูกย้ายและผสานซ้ำแบบซ้ำ
  • หากไฟล์หรือไดเรกทอรีมีอยู่ในแหล่งที่มา แต่ไม่อยู่ในปลายทางมันจะถูกย้าย
  • ไฟล์หรือไดเรกทอรีใด ๆ ที่มีอยู่แล้วในปลายทางถูกทิ้งไว้ข้างหลัง (โดยเฉพาะไดเรกทอรีที่ผสานถูกทิ้งไว้ในแหล่งที่มานี่ไม่ใช่เรื่องง่ายที่จะแก้ไข)

ระวังโค้ดที่ยังไม่ทดลอง

export dest='/path/to/destination/root'
cd /path/to/source/root
find . -type d \( -exec sh -c '[ -d "$dest/$0" ]' \; -o \
                  -exec sh -c 'mv "$0" "$dest/$0"' {} \; -prune \) \
    -o -exec sh -c '
        if ! [ -e "$dest/$0" ]; then
          mv -f "$0" "$dest/$0"
        fi
' {} \;

การแก้ไขสองรายการ: คุณต้องการ a \;before the -oon บรรทัดแรกของfindคำสั่งและคุณไม่ควรหลบหนี!ในif- เป็นเพียง!ไม่\!
llhuii

2

กระทู้นี้ออกมีปีและยังคงอันดับ # 1 ใน google ดังนั้นฉันต้องการเพิ่มวิธีอื่น ฉันมักจะทำสิ่งนี้: บรรจุเนื้อหาย่อยลงใน tarball ย้าย tarball ขึ้นไปยังไดเรกทอรีแม่แล้วแตกมันด้วยการเริ่มต้น - พฤติกรรมเขียนทับ นี่เป็นสิ่งที่คุณต้องการอย่างแน่นอน หลังจากนั้นคุณสามารถลบ subdir ของคุณได้

cd xyz
tar -cvzpf tmp.tar.gz *
mv tmp.tar.gz ../tmp.tar.gz
cd ..
tar -xvzpf tmp.tar.gz
rm -rf xyz
rm -f tmp.tar.gz

ใช้งานได้เฉพาะในกรณีที่คุณมีพื้นที่พิเศษสำหรับไฟล์ tar บีบอัด และคุณต้องการเก็บไฟล์ tar ชั่วคราวไว้หลังจากแยกหรือไม่
Anthon

แก้ไขรหัสเพื่อลบไฟล์ tmp ทุกวันนี้พื้นที่ว่างไม่ใช่ปัญหาในกรณีส่วนใหญ่ #terabyteages
Simon Kraus

0

หากคุณมีที่เก็บข้อมูลเพียงพอคุณสามารถทำได้ด้วยวิธีต่อไปนี้:

mv -bfv directory_1/* directory_2/ # all duplicate source files/directories 
                                   # will have ~ appended to them
find -name "*~" -delete            # will recursively find and delete all files 
                                   # with ~ on the end

ตรวจสอบให้แน่ใจว่าไม่มีไฟล์สำคัญใด ๆ ที่มีเครื่องหมาย ~ อยู่ท้ายไฟล์ แต่หากมีคุณสามารถเพิ่ม--suffix=whateveryouwantแทนค่าเริ่มต้นได้

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