จะใช้คำสั่ง 'cp' เพื่อแยกไดเรกทอรีที่ต้องการได้อย่างไร


411

ฉันต้องการคัดลอกไฟล์ทั้งหมดในไดเรกทอรียกเว้นบางไฟล์ในไดเรกทอรีย่อยที่ระบุ ฉันสังเกตเห็นว่าคำสั่ง 'cp' ไม่มีตัวเลือก - ยกเว้น ดังนั้นฉันจะบรรลุสิ่งนี้ได้อย่างไร



6
tar -c | tar -x?
mvds

1
@mvds เห็นด้วยกับคุณโดยใช้ tar กับ '--exclude' เป็นความคิดที่ดี
Huang F. Lei

2
สำเนาซ้ำที่เป็นไปได้ของโฟลเดอร์ซ้ำไม่รวมบางโฟลเดอร์
phuclv

คำตอบ:


704

rsync นั้นง่ายและรวดเร็ว:

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude

คุณสามารถใช้--excludeหลายครั้ง

rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude --exclude anotherfoldertoexclude

โปรดทราบว่าแบบ dir thefoldertoexcludeหลังจากที่--excludeตัวเลือกที่เป็นญาติไปคือsourcefoldersourcefolder/thefoldertoexclude

นอกจากนี้คุณสามารถเพิ่ม-nสำหรับการรันแบบแห้งเพื่อดูสิ่งที่จะถูกคัดลอกก่อนที่จะดำเนินการจริงและถ้าทุกอย่างเรียบร้อยให้ลบออก-nจากบรรทัดคำสั่ง


3
ตกลงคุณไม่สามารถเอาชนะความเรียบง่ายและพลังของ--exclude
Matthew Wilcoxson

31
เป็นthefoldertoexcludeญาติกับsourcefolderหรือ dir ทำงานปัจจุบัน? ขอบคุณ
Beebee

46
มันสัมพันธ์กับโฟลเดอร์ต้นทาง นี่จะเป็นการยกเว้นที่มาของโฟลเดอร์ / .git จากการคัดลอก rsync -r
ยกเว้น '.git

15
บางทีฉันผิด แต่ฉันคิดว่าเป็นวิธีที่ดีในการเพิ่ม "สวิตช์" ก่อน "พารามิเตอร์" นอกจากนี้หน้า man ของรายงาน rsync - ไม่รวมการใช้งานเช่นเดียวกับไวยากรณ์ "=" หรือไม่ใช้ ดังนั้นเพื่อ standarize ข้ามระบบปฏิบัติการฉันต้องการใช้rsync -av --progress --exclude="thefoldertoexclude" sourcefolder /destinationfolder- อยู่ดี upvote สำหรับ rsync แทนการค้นหาที่เป็นคุณสามารถใช้เส้นทางที่แน่นอนสำหรับแหล่งที่มาในขณะที่พบว่ามันเป็น trickier ในขณะที่มันใช้{}ใน dst
Xavi Montero

1
@munun แน่นอนเช่นจากรีโมตเซิร์ฟเวอร์ไปยังเครื่องโลคอล: $ rsync user@example.com:/var/www/mypage /var/www/mylocalpage/หรือจากโลคอลไปยังรีโมต$ rsync /var/www/mylocalpage/ user@example.com:/var/www/mypage
sobi3ch

84

ถ้าการยกเว้นรูปแบบชื่อไฟล์บางอย่างนั้นต้องถูกดำเนินการโดยยูทิลิตี้ไฟล์ยูนิกซ์ - อิชทุกไฟล์ (เช่น cp, mv, rm, tar, rsync, scp, ... ) การทำสำเนาของความพยายามครั้งยิ่งใหญ่จะเกิดขึ้น แต่สิ่งเหล่านี้สามารถทำได้โดยเป็นส่วนหนึ่งของการโค้งงอเช่นโดยเปลือก

ทุบตี

man 1 bash, extglob/

ตัวอย่าง:

$ shopt -s extglob
$ echo images / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
$ echo images /! (*. jpg)
images / 004.bmp images / 2252.png

ดังนั้นคุณเพียงแค่ใส่รูปแบบภายใน!()และมันตรงข้ามกับการแข่งขัน รูปแบบอาจมีความซับซ้อนตามอำเภอใจเริ่มจากการแจงนับเส้นทางแต่ละเส้นทาง (ตามที่ Vanwaril แสดงในคำตอบอื่น): !(filename1|path2|etc3)ไปยังสิ่งที่คล้าย regex กับดาวและคลาสอักขระ อ้างถึง manpage สำหรับรายละเอียด

zsh

man 1 zshexpn, รุ่นชื่อไฟล์/

คุณสามารถทำได้setopt KSH_GLOBและใช้รูปแบบเหมือนทุบตี หรือ,

% setopt EXTENDED_GLOB
% echo images / *
images / 004.bmp images / 033.jpg images / 1276338351183.jpg images / 2252.png
% echo images / * ~ * .jpg
images / 004.bmp images / 2252.png

ดังนั้นx~yตรงกับรูปแบบรูปแบบx แต่ไม่รวม yอีกครั้งสำหรับรายละเอียดเต็มดู manpage


ปลาใหม่!

ปลาเปลือกมีคำตอบสวยมากนี้:

🐟 cp (การจับคู่สตริง -v '* .excluded.names' - srcdir / *) destdir

โบนัสโปรเคล็ดลับ

พิมพ์cp *Hit CtrlX*แล้วดูว่าเกิดอะไรขึ้น มันไม่เป็นอันตรายฉันสัญญา


@MikailGolubtsov อาจเป็นเพราะ globbing ไม่ได้วนซ้ำและทำงานทีละระดับ แก้ไขแล้ว PS: มันทำงานในzshแต่
ulidtko

3
Nice pro-tip! วิธีนี้คุณสามารถลบรายการเดียวได้อย่างง่ายดาย ขอบคุณมาก!
taffit

BTW, setopt -u extglobการปิดคุณลักษณะการจับคู่รูปแบบในการขยายทุบตีวิ่ง
Rockallite

49

ทำไมต้องใช้rsyncเมื่อคุณสามารถทำได้:

find . -type f -not -iname '*/not-from-here/*' -exec cp '{}' '/dest/{}' ';'

สิ่งนี้จะถือว่าโครงสร้างไดเรกทอรีเป้าหมายเหมือนกันกับแหล่งที่มา


8
ฉันคิดว่าคุณต้องการ-pathอาร์กิวเมนต์เพื่อทดสอบลำดับชั้นของเส้นทางไม่ใช่ -iname
James Murty

3
และคุณจะต้องมีเซมิโคลอนในตอนท้าย:find . -type f -not -path '*/not-from-here/*' -exec cp '{}' '/dest/{}' \;
Matthew Wilcoxson

1
ว้าวมันจะไม่ให้ฉัน: "การแก้ไขต้องมีอย่างน้อย 6 ตัวอักษร"!
Matthew Wilcoxson

1
@MatthewWilcoxson Meh ข้อ จำกัด เหล่านั้นจะถูกยกเลิกทันทีที่คุณได้รับตัวแทนเพิ่มอีกเล็กน้อย ฉันแก้ไขคำตอบตามนั้น ขอบคุณอีกครั้ง!
Linus Kleen

1
@ Henning ทำไมไม่rsync? เพราะมันอาจจะไม่ปรากฏในระบบ! ในขณะที่find, cpเสมอในสถานที่ของพวกเขา หรือคุณจากคนที่ติดตั้ง 2gigs ของสิ่งที่ทำสิ่งที่ง่าย
Reishin

37
cp -r `ls -A | grep -v "c"` $HOME/

1
ทำงานให้ฉันใน Windows 10
.sh

สร้างฟังก์ชั่นเชลล์ซึ่งจะลดความยุ่งยากในการใช้งานสำหรับพา ธ ต้นทางที่กำหนดเองและการแยกไฟล์หรือไดเรกทอรีเพียงไฟล์เดียว: # $1 = source path # $2 = destination path # $3 = filter copy_from_source_to_destination_except_filter() { cp -r $(ls -A $1 | grep -v -w $3 | awk -v path=$1 '{printf "%s/%s ", path, $1}') $2 }
ElectRocnic

ล้มเหลวด้วยไดเรกทอรีที่มีช่องว่าง
Sérgio

27

วิธีที่ง่ายที่สุดที่ฉันพบซึ่งคุณสามารถคัดลอกไฟล์ทั้งหมดยกเว้นไฟล์และโฟลเดอร์เพียงแค่เพิ่มชื่อไว้ในวงเล็บ:

shopt -s extglob
cp -r !(Filename1 | FoldernameX | Filename2) Dest/

9
ไม่ได้ผลสำหรับฉัน ฉันได้รับ-bash: !: event not found
geneorama

8
shopt -s extglob (ดำเนินการสิ่งนี้เพื่อเปิดใช้งาน! ใน cp, rm และอื่น ๆ )
imkost


10

มันสัมพันธ์กับไดเรกทอรีต้นทาง
นี่จะเป็นการยกเว้นไดเรกทอรีที่source/.gitจะคัดลอก

rsync -r --exclude '.git' source target

ความแตกต่าง / การปรับปรุงเปรียบเทียบกับคำตอบยอดนิยมคืออะไร?
ลดกิจกรรม

8

rsync

rsync -r --verbose --exclude 'exclude_pattern' ./* /to/where/

และก่อนอื่นให้ลองด้วยตัวเลือก -n เพื่อดูว่าจะคัดลอกอะไร


ความแตกต่าง / การปรับปรุงเปรียบเทียบกับคำตอบยอดนิยมคืออะไร?
ลดกิจกรรม

7

ฉันคิดว่าคุณกำลังใช้ bash หรือ dash จะใช้งานได้ไหม

shopt -s extglob  # sets extended pattern matching options in the bash shell
cp $(ls -laR !(subdir/file1|file2|subdir2/file3)) destination

การทำ ls ไม่รวมไฟล์ที่คุณไม่ต้องการและใช้มันเป็นอาร์กิวเมนต์แรกสำหรับ cp


9
คุณสามารถข้ามพิเศษและก็ทำls cp !(file1|file1) dest
Shawn Chin

ห้ามใช้ -laR เพิ่มสตริงที่รบกวน cp cp $(ls folder/!exclude_folder0|exclude_folder1)) dest
LAL

5

อีกตัวเลือกที่ง่ายกว่าคือการติดตั้งและใช้ rsync ซึ่งมีตัวเลือก --exclude-dir และสามารถใช้สำหรับไฟล์ทั้งในตัวเครื่องและจากระยะไกล


4

rsyncจริงๆแล้วค่อนข้างยุ่งยาก ต้องทำหลาย ๆ การทดสอบเพื่อให้มันใช้งานได้

สมมติว่าคุณต้องการคัดลอก/var/www/htmlไป/var/www/devแต่จำเป็นที่จะต้องยกเว้น /var/www/html/site/video/ไดเรกทอรีอาจเนื่องจากขนาดของมัน คำสั่งจะเป็น:

rsync -av --exclude 'sites/video' /var/www/html/ /var/www/dev

ข้อแม้บางอย่าง:

  1. /จำเป็นต้องใช้สแลชสุดท้ายในแหล่งข้อมูลมิฉะนั้นจะคัดลอกไดเรกทอรีต้นทางแทนที่จะเป็นเนื้อหาและกลายเป็น/var/www/dev/html/xxxxซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ
  2. ที่--excludeเส้นทางเป็นญาติกับแหล่งที่มาโดยตรง แม้ว่าคุณจะใส่เส้นทางที่สมบูรณ์ แต่ก็จะไม่ทำงาน

  3. -vสำหรับ verbose -aสำหรับโหมดเก็บถาวรซึ่งหมายความว่าคุณต้องการเรียกซ้ำและต้องการรักษาเกือบทุกอย่าง


ทางออกง่ายๆที่คำนึงถึงตัวละครพิเศษและพื้นที่สีขาว
Sérgio

ขอบคุณที่อธิบายพารามิเตอร์ต่างจากคำตอบยอดนิยมปัจจุบัน!
ลดกิจกรรม

3
cp -rv `ls -A | grep -vE "dirToExclude|targetDir"` targetDir

แก้ไข: ลืมที่จะยกเว้นเส้นทางเป้าหมายเช่นกัน (ไม่เช่นนั้นจะเป็นการคัดลอกซ้ำ)


4
ระวังรายการไดเรกทอรีที่มีช่องว่าง
เปาโล Scardine

3

นี่คือการแก้ไขคำตอบของ Linus Kleen คำตอบของเขาไม่ทำงานสำหรับฉันเพราะจะมี เพิ่มไว้ด้านหน้าของพา ธ ไฟล์ที่ cp ไม่ชอบ (พา ธ จะดูเหมือน source / .destination / file)

คำสั่งนี้ใช้ได้สำหรับฉัน:

find . -type f -not -path '*/exlude-path/*' -exec cp --parents '{}' '/destination/' \;

คำสั่ง --parents เก็บรักษาโครงสร้างไดเร็กทอรี


2

เพียงแค่ย้ายมันชั่วคราวไปยังไดเรกทอรีที่ซ่อนอยู่ (และเปลี่ยนชื่อหลังจากถ้าต้องการ)

mkdir .hiddendir
cp * .hiddendir -R
mv .hiddendir realdirname

1
อาจจะไม่สวย - แต่นี้เป็นตัวเลือกเดียวที่ฉันได้พบได้ที่นี่ซึ่งทำงานร่วมกับcpและมาตรฐาน POSIX shเปลือกเช่น
tomekwi

1
คำตอบนี้มีการประเมินต่ำเกินไป นี่เป็นคำตอบที่อ่านง่ายและเข้าใจได้ง่ายที่สุด รุ่งโรจน์ฉันไม่รู้ว่าทำไมฉันไม่คิดอย่างนั้น
Robert Talada

ขอบคุณ @RobertTalada คำตอบจะไปได้ไกลแค่ไหน? ️‍🌈
lama12345


0

ฉันใช้การวนรอบ "ทำในขณะที่" เพื่ออ่านผลลัพธ์ของคำสั่ง find ในตัวอย่างนี้ฉันกำลังจับคู่ (แทนที่จะยกเว้น) รูปแบบบางอย่างเนื่องจากมีจำนวนรูปแบบที่ จำกัด ที่ฉันต้องการมากกว่าที่ฉันไม่ต้องการ คุณสามารถย้อนกลับตรรกะด้วย -not ที่ด้านหน้าของแฟล็ก -iname:

    find . -type f -iname "*.flac" -o -print0 -iname "*.mp3" -print0 -o -iname "*.wav" -print0 -o -iname "*.aac" -print0 -o -iname "*.wma" -print0 | while read -d $'\0' file; do cp -ruv "$file" "/media/wd/network_sync/music/$file"; done

ฉันใช้ข้างต้นเพื่อคัดลอกไฟล์ประเภทเพลงทั้งหมดที่ใหม่กว่าบนเซิร์ฟเวอร์ของฉันมากกว่าไฟล์ใน Western Digital TV Live Hub ที่ฉันติดตั้งที่ / media / wd ฉันใช้ข้างต้นเพราะฉันมีไฟล์ DVD, mpegs และอื่น ๆ จำนวนมากที่ฉันต้องการยกเว้นและเพราะเหตุผลบางประการ rsync ดูเหมือนว่ามันเป็นการคัดลอก แต่หลังจากที่ฉันดูอุปกรณ์ wd ไฟล์จะไม่อยู่ที่นั่นแม้จะไม่มี ข้อผิดพลาดระหว่าง rsync ด้วยคำสั่งนี้:

    rsync -av --progress --exclude=*.VOB --exclude=*.avi --exclude=*.mkv --exclude=*.ts --exclude=*.mpg --exclude=*.iso --exclude=*ar --exclude=*.vob --exclude=*.BUP --exclude=*.cdi --exclude=*.ISO --exclude=*.shn --exclude=*.MPG --exclude=*.AVI --exclude=*.DAT --exclude=*.img --exclude=*.nrg --exclude=*.cdr --exclude=*.bin --exclude=*.MOV --exclude=*.goutputs* --exclude=*.flv --exclude=*.mov --exclude=*.m2ts --exclude=*.cdg --exclude=*.IFO --exclude=*.asf --exclude=*.ite /media/2TB\ Data/data/music/* /media/wd/network_sync/music/

0
ls -I "filename1" -I "filename2" | xargs cp -rf -t destdir 

ส่วนแรกlsไฟล์ทั้งหมด -Iแต่เฉพาะไฟล์ที่ซ่อนอยู่กับธง เอาต์พุตของlsใช้เป็นอินพุตมาตรฐานสำหรับส่วนที่สอง xargsสร้างและดำเนินการคำสั่งcp -rf -t destdirจากอินพุตมาตรฐาน ธง-rหมายถึงการคัดลอกไดเรกทอรีซ้ำ-fหมายถึงการคัดลอกไฟล์บังคับซึ่งจะเขียนทับไฟล์ในdestdir, -tระบุสำเนาไดเรกทอรีปลายทาง


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