ฉันจะดำเนินการ "คัดลอกหากมีการเปลี่ยนแปลง" ได้อย่างไร?


34

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

หากต้องการอธิบายรายละเอียดเล็กน้อยเกี่ยวกับกรณีการใช้งานของฉัน: ฉันกำลังสร้าง.cไฟล์จำนวนมากในไดเรกทอรีชั่วคราว (โดยวิธีการที่จะสร้างไฟล์ทั้งหมดโดยไม่มีเงื่อนไข) และเมื่อฉันสร้างไฟล์ขึ้นมาใหม่ฉันต้องการคัดลอกเท่านั้น รายการที่เปลี่ยนไปเป็นไดเรกทอรีต้นทางจริงปล่อยให้รายการที่ไม่มีการเปลี่ยนแปลง (ด้วยเวลาการสร้างเก่า) เพื่อที่makeจะรู้ว่าไม่จำเป็นต้องคอมไพล์ใหม่ (ไม่ใช่ไฟล์ที่สร้างขึ้นทั้งหมดเป็น.cไฟล์ดังนั้นฉันต้องทำการเปรียบเทียบแบบไบนารีมากกว่าการเปรียบเทียบข้อความ)

(ตามที่ทราบ: นี่เป็นคำถามที่เกิดขึ้นฉันถามบนhttps://stackoverflow.com/questions/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981762#8981762ซึ่งฉันพยายามอยู่ เพื่อเพิ่มความเร็วให้กับไฟล์สคริปต์ที่ฉันใช้ในการดำเนินการนี้ แต่มันเกิดขึ้นกับฉันว่าฉันควรถามว่ามีวิธีที่ดีกว่าในการทำสิ่งนี้มากกว่าการเขียนสคริปต์ของตัวเองโดยเฉพาะอย่างยิ่งตั้งแต่วิธีง่ายๆในการทำเชลล์ สคริปต์จะเรียกใช้บางอย่างเช่นcmpไฟล์ทุกคู่และการเริ่มต้นกระบวนการทั้งหมดใช้เวลานานเกินไป)


1
คุณสามารถใช้diff -qr dirA dirBเพื่อดูว่าไฟล์ใดที่ไม่ซ้ำกันdirAและdirBrepectively

1
@ brooks-moses นี่เป็นงานที่เหมาะสำหรับccache !
aculich

3
@hesse ถ้าคุณต้องการที่จะแสดงไฟล์ที่ไม่ซ้ำกันคุณสามารถใช้ diff แต่ถ้าคุณต้องการที่จะเห็นเพียงแค่สิ่งที่มีการเปลี่ยนแปลงแล้วใช้หรือทางยาวrsync -avnc rsync --archive --verbose --dry-run --checksum
aculich

คำตอบ:


29

rsync น่าจะเป็นเครื่องมือที่ดีที่สุดสำหรับเรื่องนี้ มีจำนวนมากของตัวเลือกอยู่ในคำสั่งนี้เพื่ออ่านหน้าคน ฉันคิดว่าคุณต้องการตัวเลือก --checksum หรือ --ignore-times


ฉันควรสังเกตว่าฉันได้ลองแล้วโดยไม่ประสบความสำเร็จ ทั้งสองตัวเลือกเหล่านี้มีผลกับว่า rsync ทำสำเนา - แต่ถึงแม้ว่ามันจะไม่ทำการคัดลอกมันก็จะปรับปรุงเวลาการแก้ไขของไฟล์เป้าหมายให้เหมือนกับแหล่งที่มา (ถ้าระบุ-tตัวเลือก) หรือเวลาการซิงโครไนซ์ (ถ้า-tไม่ได้ระบุ)
Brooks Moses

4
@Brooks โมเสส: มันไม่ได้ อย่างน้อยเวอร์ชันของฉันrsyncก็ไม่ได้ ถ้าผมทำนี้mkdir src dest; echo a>src/a; rsync -c src/* dest; sleep 5; touch src/a; rsync -c src/* destแล้วstat dest/aแสดงให้เห็น mtime และ ctime 5 src/aวินาทีที่เก่ากว่าคนของ
กัส

@angus: อืม โอเคคุณพูดถูก คีย์ดูเหมือนจะเป็น--checksumตัวเลือกและแม้ว่าlinux.die.net/man/1/rsyncจะไม่มีสิ่งใดที่บ่งบอกว่ามันมีผลกระทบใด ๆ กับว่าวันที่แก้ไขนั้นได้รับการอัปเดตหรือไม่อย่างไรก็ตามยังทำให้วันที่แก้ไขปลายทางถูกทิ้งไว้ มิได้ถูกแตะต้อง (ในทางกลับกัน--ignore-timesตัวเลือกไม่มีผลกระทบนี้พร้อมกับวันที่แก้ไขยังคงได้รับการปรับปรุง) ระบุว่าสิ่งนี้ดูเหมือนว่าจะไม่มีเอกสารทั้งหมดแม้ว่าฉันจะพึ่งพาได้หรือไม่
Brooks Moses

2
@BrooksMoses: ฉันคิดว่าคุณสามารถพึ่งพาได้: rsyncเวิร์กโฟลว์คือ: 1) ตรวจสอบว่าไฟล์นั้นจำเป็นต้องได้รับการปรับปรุงหรือไม่; 2) ถ้าเป็นเช่นนั้นอัปเดตไฟล์ --checksumตัวเลือกที่จะบอกว่ามันไม่ควรได้รับการปรับปรุงเพื่อให้rsyncไม่ควรดำเนินการขั้นตอนที่ 2)
enzotib

2
@BrooksMoses: --ignore-timesโดยไม่--checksumคัดลอกทุกไฟล์และปรับปรุงการประทับเวลาแม้ว่าไฟล์จะเหมือนกันก็ตาม
enzotib

13

คุณสามารถใช้-uสวิตช์cpเพื่อ:

$ cp -u [source] [destination]

จากหน้าคน:

   -u, --update
       copy only when the SOURCE file is newer than the destination file or 
       when the destination file is missing

4
สวัสดีและยินดีต้อนรับสู่เว็บไซต์ เราคาดว่าคำตอบจะมีความสำคัญมากกว่านี้ ตัวอย่างเช่นคุณอาจรวมถึงคำอธิบายว่า-uธงทำอะไรและทำงานอย่างไรและจะช่วย OP ได้อย่างไร อย่างไรก็ตามในกรณีนี้มันไม่ช่วย OP เนื่องจากมันจะคัดลอกไฟล์ที่เหมือนกันถ้ามันใหม่กว่าและเปลี่ยนการประทับเวลาซึ่งเป็นสิ่งที่ OP ต้องการหลีกเลี่ยงอย่างแน่นอน
terdon

1
จากความคิดเห็นเกี่ยวกับ A ที่คล้ายกันซึ่งถูกลบไปแล้ว: "สิ่งนี้จะไม่ทำงานเนื่องจากมันจะคัดลอกไฟล์เหมือนกันถ้าการประทับเวลาของแหล่งที่มาเป็นรุ่นที่ใหม่กว่า (และอัปเดตเวลาประทับของปลายทาง
slm

ไม่ตอบคำถามเลย แต่ฉันก็ยังพบว่ามีประโยชน์
user31389

7

ในขณะที่ใช้งานrsync --checksumเป็นวิธีทั่วไปที่ดีในการ "คัดลอกหากมีการเปลี่ยนแปลง" ในกรณีเฉพาะของคุณมีทางออกที่ดีกว่า!

หากคุณต้องการหลีกเลี่ยงการรวบรวมไฟล์ซ้ำโดยไม่จำเป็นคุณควรใช้ccacheซึ่งสร้างขึ้นเพื่อจุดประสงค์นี้! ในความเป็นจริงไม่เพียง แต่จะหลีกเลี่ยงการ recompiles ที่ไม่จำเป็นของไฟล์ที่สร้างขึ้นโดยอัตโนมัติของคุณก็จะยังมีสิ่งความเร็วขึ้นเมื่อใดก็ตามที่คุณทำmake cleanและรวบรวมอีกครั้งจากรอยขีดข่วน

ต่อไปฉันแน่ใจว่าคุณจะถามว่า "ปลอดภัยหรือไม่" ดีใช่เป็นเว็บไซต์ที่ชี้ให้เห็น:

ปลอดภัยไหม

ใช่. สิ่งที่สำคัญที่สุดของแคชคอมไพเลอร์คือการสร้างเอาต์พุตที่ตรงกับที่คอมไพเลอร์จริงจะสร้างเสมอ ซึ่งรวมถึงการให้ไฟล์ออบเจ็กต์เดียวกันและคำเตือนของคอมไพเลอร์เดียวกันที่จะเกิดขึ้นหากคุณใช้คอมไพเลอร์จริง วิธีเดียวที่คุณควรจะบอกได้ว่าคุณกำลังใช้ ccache คือความเร็ว

และมันใช้งานง่ายเพียงแค่เพิ่มมันเป็นคำนำหน้าในCC=บรรทัด makefile ของคุณ (หรือคุณสามารถใช้ symlink ได้ แต่วิธี makefile น่าจะดีกว่า)


1
ตอนแรกฉันเข้าใจผิดและคิดว่าคุณแนะนำให้ฉันใช้ ccache เป็นส่วนหนึ่งของการสร้าง แต่ตอนนี้ฉันเข้าใจแล้ว - ข้อเสนอแนะของคุณคือฉันเพียงคัดลอกไฟล์ทั้งหมดแล้วใช้ ccache ในกระบวนการสร้างจึงหลีกเลี่ยงการสร้างใหม่ที่ ไม่ได้เปลี่ยน มันเป็นความคิดที่ดี แต่ในกรณีของฉันจะทำได้ไม่ดี - ฉันมีไฟล์หลายร้อยไฟล์โดยปกติจะเปลี่ยนครั้งละหนึ่งหรือสองครั้งเท่านั้นและทำงานภายใต้ Cygwin ที่เริ่มกระบวนการ ccache หลายร้อยครั้งเพื่อดูแต่ละไฟล์ ไฟล์จะใช้เวลาหลายนาที ถึงกระนั้นก็ถูกโหวตเพราะมันเป็นคำตอบที่ดีสำหรับคนส่วนใหญ่!
Brooks Moses

ไม่ฉันไม่ได้แนะนำให้คุณคัดลอกไฟล์ทั้งหมด แต่คุณสามารถสร้างไฟล์. c อัตโนมัติในสถานที่ได้ (ลบขั้นตอนการคัดลอกและเขียนลงไปโดยตรง) แล้วก็ใช้ ccache ฉันไม่รู้ว่าคุณหมายถึงอะไรโดยเริ่มกระบวนการ ccache หลายร้อย ... มันเป็นเพียงกระดาษห่อหุ้มน้ำหนักเบารอบ gcc ที่ค่อนข้างเร็วและจะเร่งการสร้างส่วนอื่น ๆ ของโครงการอีกด้วย คุณเคยลองใช้มันหรือยัง? ฉันต้องการดูการเปรียบเทียบเวลาระหว่างการใช้วิธีคัดลอกและ ccache ของคุณ ในความเป็นจริงคุณสามารถรวมสองวิธีเพื่อให้ได้ประโยชน์จากทั้งสองอย่าง
aculich

1
ใช่ตอนนี้ฉันเข้าใจเกี่ยวกับการคัดลอกแล้ว ในการชี้แจงสิ่งที่ฉันหมายถึงคือ: ถ้าฉันสร้างไฟล์ในสถานที่ฉันต้องโทรccache file.c -o file.oหรือเทียบเท่าหลายร้อยครั้งเพราะมีหลายร้อยfile.cไฟล์ เมื่อฉันได้ทำที่มีcmpมากกว่าccacheก็ใช้เวลาหลายนาที - และเป็นน้ำหนักเบาเป็นcmp ccacheปัญหาคือว่าใน Cygwin การเริ่มต้นกระบวนการต้องใช้เวลาที่ไม่สำคัญแม้กระทั่งสำหรับกระบวนการที่ไม่สมบูรณ์
Brooks Moses

1
ในฐานะ datapoint for f in src/*; do /bin/true.exe; doneใช้เวลา 30 วินาทีดังนั้นใช่ อย่างไรก็ตามฉันชอบโปรแกรมแก้ไขที่ใช้ Windows ของฉันและนอกเหนือจากปัญหาเรื่องเวลาแบบนี้ Cygwin ทำงานได้ดีกับเวิร์กโฟลว์ของฉันเนื่องจากเป็นสถานที่ที่มีน้ำหนักเบาเพื่อทดสอบสิ่งต่างๆในท้องถิ่นหากฉันไม่ได้อัปโหลดไปยังเซิร์ฟเวอร์การสร้าง มันมีประโยชน์ที่จะมีเชลล์และตัวแก้ไขในระบบปฏิบัติการเดียวกัน :)
Brooks Moses

1
หากคุณต้องการใช้โปรแกรมแก้ไขที่ใช้ Windows คุณสามารถทำได้อย่างง่ายดายด้วยShared Folders ถ้าคุณติดตั้ง Guest Additions ... แต่ถ้า Cygwin เหมาะสมกับคุณแล้วฉันจะพูดยังไงดีล่ะ? ดูเหมือนความอัปยศที่ต้องกระโดดผ่านห่วงแปลก ๆ เช่นนี้ ... และการรวบรวมโดยทั่วไปจะเร็วขึ้นใน VM เช่นกัน
aculich

3

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

diff -qr ./x ./y | awk '{print $2}' | xargs -n1 -J% cp % ./y/

ที่ไหน:

  • x คือโฟลเดอร์ที่อัปเดต / ใหม่ของคุณ
  • y คือปลายทางที่คุณต้องการคัดลอก
  • awk จะใช้อาร์กิวเมนต์ที่สองของแต่ละบรรทัดจากคำสั่ง diff (บางทีคุณอาจต้องการสิ่งพิเศษสำหรับชื่อไฟล์ที่มีช่องว่าง - ไม่สามารถลองได้ในตอนนี้)
  • xargs -J% จะแทรกชื่อไฟล์ไปยัง cp ในตำแหน่งที่เหมาะสม

1
-1 เนื่องจากมีความซับซ้อนมากเกินไปไม่ใช่พกพา ( -Jเป็น bsd เฉพาะกับ GNU xargs เป็น-I) และทำงานไม่ถูกต้องหากไฟล์ชุดเดียวกันไม่มีอยู่ในทั้งสองตำแหน่งแล้ว (ถ้าฉันtouch x/boogrep ให้ฉันOnly in ./x: booซึ่งทำให้เกิดข้อผิดพลาดในไปป์ไลน์) rsync --checksumใช้เครื่องมือที่สร้างขึ้นสำหรับงานเช่น
aculich

หรือดีกว่ายังสำหรับเฉพาะกรณีการใช้งานนี้ccache
aculich

+1 เนื่องจากเป็นชุดคำสั่งที่รู้จักกันดีที่ฉันสามารถใช้ในงานที่คล้ายกัน (มาที่นี่เพื่อทำ diff), rsync อาจยังดีกว่าสำหรับงานนี้โดยเฉพาะ
ntg

3

ผมชอบที่จะใช้ความพร้อมเพรียงกันในความโปรดปรานของrsyncเพราะสนับสนุนโทหลายที่มีการติดตั้งแล้วคีย์ SSH ของฉันและ VPN แยกต่างหาก

ดังนั้นใน crontab ของฉันเพียงโฮสต์เดียวฉันให้พวกเขาประสานทุก 15 นาที:

** dev -logfile /tmp/sync.master.dev.log) &> /tmp/sync.master.dev.log

จากนั้นฉันสามารถพัฒนาได้ทั้งสองด้านและการเปลี่ยนแปลงจะเผยแพร่ ในความเป็นจริงสำหรับโครงการสำคัญฉันมีเซิร์ฟเวอร์ไม่เกิน 4 เซิร์ฟเวอร์ที่สะท้อนแผนผังเดียวกัน (3 รันพร้อมเพรียงจาก cron ชี้ไปยังเซิร์ฟเวอร์ที่ไม่มี) ในความเป็นจริง Linux และ Cygwin มีโฮสต์ที่หลากหลาย - ยกเว้นอย่าคาดหวังว่าจะมีการเชื่อมโยงที่นุ่มนวลใน win32 นอกสภาพแวดล้อมของ cygwin

หากคุณไปเส้นทางนี้ให้ทำมิรเรอร์เริ่มต้นในด้านที่ว่างโดยไม่มี-batchเช่น

unison -ui text  -times /home/master ssh://192.168.1.12//home/master -path dev

แน่นอนว่ามีการกำหนดค่าให้ละเว้นไฟล์สำรองข้อมูลที่เก็บถาวรและอื่น ๆ :

 ~/.unison/default.prf :
# Unison preferences file
ignore = Name {,.}*{.sh~}
ignore = Name {,.}*{.rb~}
ignore = Name {,.}*{.bak}
ignore = Name {,.}*{.tmp}
ignore = Name {,.}*{.txt~}
ignore = Name {,.}*{.pl~}
ignore = Name {.unison.}*
ignore = Name {,.}*{.zip}

    # Use this command for displaying diffs
    diff = diff -y -W 79 --suppress-common-lines

    ignore = Name *~
    ignore = Name .*~
    ignore = Path */pilot/backup/Archive_*
    ignore = Name *.o

ฉันดูแล้ว แต่ไม่พบunisonตัวเลือกที่หมายถึง "ไม่อัปเดตวันที่แก้ไขไฟล์ล่าสุด" มีหรือไม่ มิฉะนั้นนี่เป็นคำตอบที่ดีสำหรับปัญหาที่แตกต่างอย่างสิ้นเชิง
Brooks Moses

1
-timesทำเพื่อฉัน พร้อมเพรียงมีโหมดแห้งด้วยเช่นกันฉันคิดว่า
Marcos

การตั้งค่าtimes=false(หรือเลิก-times) จะทำเช่นนั้น ฉันไม่รู้ว่าฉันพลาดสิ่งนั้นในเอกสารประกอบก่อนหน้านี้อย่างไร ขอบคุณ!
Brooks Moses

ดีใจที่ได้ช่วยเหลือ ฉันเป็นคนขี้เหนียวเมื่อพูดถึงการอนุรักษ์สิ่งต่าง ๆ เช่น modtimes การอนุญาตและซอฟต์ลิงค์ มักถูกมองข้าม
มาร์กอส

1

ในขณะที่rsync --checksumเป็นคำตอบที่ถูกต้องทราบว่าตัวเลือกนี้ไม่สามารถใช้กับ--timesและนั่น--archiveรวมถึง--timesดังนั้นหากคุณต้องการคุณจริงๆต้องrsync -a --checksumrsync -a --no-times --checksum


คุณหมายถึงอะไรโดยพูดว่า 'ไม่เข้ากัน'
OV

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