tar - ยกเว้นไม่รวม ทำไม?


71

ฉันมีบรรทัดที่ง่ายมากในสคริปต์ทุบตีซึ่งดำเนินการสำเร็จ (เช่นการผลิต_data.tarไฟล์) ยกเว้นว่าจะไม่แยกไดเรกทอรีย่อยที่มีการบอกว่าไม่รวมผ่าน--excludeตัวเลือก:

/bin/tar -cf /home/_data.tar  --exclude='/data/sub1/*'  --exclude='/data/sub2/*' --exclude='/data/sub3/*'  --exclude='/data/sub4/*'  --exclude='/data/sub5/*'  /data

แต่จะสร้าง_data.tarไฟล์ที่มีทุกอย่างภายใต้ / data รวมถึงไฟล์ในไดเรกทอรีย่อยที่ฉันต้องการยกเว้น

มีความคิดอะไรไหม และจะแก้ไขได้อย่างไร

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

/bin/tar -cf /home/_data.tar  /data  --exclude='/data/sub1/*'  --exclude='/data/sub2/*'  --exclude='/data/sub3/*'  --exclude='/data/sub4/*'  --exclude='/data/sub5/*'

แต่นั่นไม่ได้ช่วย ไดเร็กทอรีย่อย "ที่แยกออก" ทั้งหมดมีอยู่ใน_data.tarไฟล์ผลลัพธ์

นี่ทำให้งง ไม่ว่าจะเป็นข้อผิดพลาดใน tar ปัจจุบัน (GNU tar 1.23, บน CentOS 6.2, Linux 2.6.32) หรือ "ความไวสูง" ของ tar ไปยังช่องว่างและการพิมพ์ผิดพลาดอื่น ๆ ง่าย ๆ ฉันถือว่าข้อผิดพลาดนี้ สำหรับตอนนี้.

นี่มันแย่มาก : ฉันลองใช้ความเห็นที่แนะนำด้านล่าง (ไม่มีส่วนท้าย/*) และยังไม่สามารถใช้งานได้ในสคริปต์การผลิต:

/bin/tar -cf /home/_data.tar  /data  --exclude='/data/sub1'  --exclude='/data/sub2'  --exclude='/data/sub3'  --exclude='/data/sub4'

ฉันไม่เห็นความแตกต่างระหว่างสิ่งที่ฉันลองและสิ่งที่ @Richard Perrin ลองยกเว้นราคาและ 2 ช่องว่างแทน 1 ฉันจะลองสิ่งนี้ (ต้องรอให้สคริปต์ทุกคืนทำงานเป็นไดเรกทอรีที่จะสำรองข้อมูล ขึ้นมาก) และรายงานกลับ

/bin/tar -cf /home/_data.tar  /data --exclude=/data/sub1 --exclude=/data/sub2 --exclude=/data/sub3 --exclude=/data/sub4

ฉันเริ่มที่จะคิดว่าความtar --excludeไวเหล่านี้ทั้งหมดไม่ใช่น้ำมันดิน แต่มีอะไรบางอย่างในสภาพแวดล้อมของฉัน

มันได้ผล! ความพยายามครั้งสุดท้าย (ไม่มีเครื่องหมายคำพูดเดี่ยวและเว้นวรรคเดียวแทนการเว้นวรรคสองครั้งระหว่างการ--excludeทดสอบ) แปลก แต่ก็ยอมรับ

เหลือเชื่อ! ปรากฎว่ารุ่นเก่ากว่าของtar(1.15.1) จะยกเว้นเฉพาะในกรณีที่ dir ระดับบนสุดเป็นบรรทัดสุดท้ายในบรรทัดคำสั่ง ตรงข้ามกับที่เวอร์ชั่น 1.23 ต้องการ FYI

คำตอบ:


50

หากคุณต้องการยกเว้นไดเรกทอรีทั้งหมดรูปแบบของคุณควรตรงกับไดเรกทอรีนั้นไม่ใช่ไฟล์ภายใน ใช้--exclude=/data/sub1แทน--exclude='/data/sub1/*'

ระวังด้วยการพูดรูปแบบเพื่อป้องกันพวกเขาจากการขยายตัวเปลือก

ดูตัวอย่างนี้ด้วยปัญหาในการเรียกใช้ครั้งสุดท้าย:

$ for i in 0 1 2; do mkdir -p /tmp/data/sub$i; echo foo > /tmp/data/sub$i/foo; done
$ find /tmp/data
/tmp/data
/tmp/data/sub2
/tmp/data/sub2/foo
/tmp/data/sub0
/tmp/data/sub0/foo
/tmp/data/sub1
/tmp/data/sub1/foo
$ tar -zvcf /tmp/_data.tar /tmp/data --exclude='/tmp/data/sub[1-2]'
tar: Removing leading `/' from member names
/tmp/data/
/tmp/data/sub0/
/tmp/data/sub0/foo
$ tar -zvcf /tmp/_data.tar /tmp/data --exclude=/tmp/data/sub[1-2]
tar: Removing leading `/' from member names
/tmp/data/
/tmp/data/sub0/
/tmp/data/sub0/foo
$ echo tar -zvcf /tmp/_data.tar /tmp/data --exclude=/tmp/data/sub[1-2]
tar -zvcf /tmp/_data.tar /tmp/data --exclude=/tmp/data/sub[1-2]
$ tar -zvcf /tmp/_data.tar /tmp/data --exclude /tmp/data/sub[1-2]
tar: Removing leading `/' from member names
/tmp/data/
/tmp/data/sub2/
/tmp/data/sub2/foo
/tmp/data/sub0/
/tmp/data/sub0/foo
/tmp/data/sub2/
tar: Removing leading `/' from hard link targets
/tmp/data/sub2/foo
$ echo tar -zvcf /tmp/_data.tar /tmp/data --exclude /tmp/data/sub[1-2]
tar -zvcf /tmp/_data.tar /tmp/data --exclude /tmp/data/sub1 /tmp/data/sub2

ขอบคุณสำหรับคำตอบที่เน้นและชัดเจน เกี่ยวกับประเด็นแรกของคุณฉันพยายามทำตามคำแนะนำในหัวข้อ LQนี้ ฉันไม่แน่ใจว่าสิ่งที่ฉันพลาดไป แต่ตอนนี้ฉันได้อ่านประเด็นที่สองของคุณแล้ว ฉันจะลองแล้วรายงานกลับ +1 สำหรับตอนนี้
ateiob

สิ่งที่ผมสังเกตเห็นก็คือ--exclude b(พื้นที่แทนเครื่องหมายเท่ากับ) --exclude=bกับ สิ่งนี้สร้างความแตกต่างหรือไม่? (ไม่ควร IMHO)
ateiob

1
เครื่องหมายที่เท่าเทียมกันอาจเป็นสิ่งจำเป็นเพื่อหลีกเลี่ยงการขยายตัวของเชลล์ในรูปแบบที่ไม่ได้ยกมา หากคุณมีช่องว่างแทนรูปแบบที่ไม่มีเครื่องหมายสามารถขยายได้โดยเชลล์ไปยังอาร์กิวเมนต์ --exclude เดียวและการขยายที่เหลือให้เป็นไฟล์เพื่อเพิ่มลงในไฟล์ tar ตัวอย่างข้างต้นทั้งหมดของคุณมี '=' - หากสคริปต์ไม่มีและไม่มีเครื่องหมายคำพูดเดียวนั่นก็เป็นสาเหตุของปัญหาของคุณ
R Perrin

ตกลง. ฉันทดสอบตัวอย่างของคุณบนกล่องและใช้งานได้แม้จะมีหลาย--exclude=แบบในบรรทัดเดียวกัน ดังนั้นความแตกต่างจะต้องเป็นงี่เง่า/*ที่ฉันผนวกเข้ากับแต่ละไดเรกทอรีย่อย ฉันจะทดสอบคืนนี้ในสคริปต์การผลิตและรายงานกลับ +1 อีก
ateiob

สำหรับฉันคำตอบจาก @carlo เป็นปัญหาเฉพาะ - tar โง่ไม่สามารถใช้ - ยกเว้นเป็นตัวเลือกสุดท้ายในบรรทัดคำสั่ง - เห็นได้ชัดว่าทำให้เกิดอาการปวดหัวจำนวนมาก ขอบคุณทุกคน
moodboom

32

อาจเป็นไปได้ว่าเวอร์ชั่นของคุณtarต้องการ--excludeตัวเลือกที่จะต้องวางไว้ที่จุดเริ่มต้นของtarคำสั่ง

ดู: https://stackoverflow.com/q/984204

tar --exclude='./folder' --exclude='./upload/folder2' \
    -zcvf /backup/filename.tgz .

ดู: http://mandrivausers.org/index.php?/topic/8585-multiple-exclude-in-tar/

tar --exclude=<first> --exclude=<second> -cjf backupfile.bz2 /home/*

ทางเลือก:

EXCLD='first second third'
tar -X <(for i in ${EXCLD}; do echo $i; done) -cjf backupfile.bz2 /home/*

tarเคล็ดลับคำสั่งอื่นมาจากที่นี่ :

tar cvfz myproject.tgz --exclude='path/dir_to_exclude1' \
                       --exclude='path/dir_to_exclude2' myproject

ดูการอัปเดตของฉันด้านบน รูปแบบล่าสุดที่ทดลองใช้ (ไม่มีเครื่องหมายอัญประกาศเว้นวรรค) ฉันมีความคิดว่าทำไมไม่มี. +1 สำหรับคำตอบ + ลิงก์ที่คิดอย่างดี
ateiob

FYI ภายใต้เดเบียนถ้าฉันไม่แม่นยำตัวกรองเช่น--exclude=mydir/*นั้นมันไม่ทำงาน (โดยใช้tar --exclude=maindir/mydir/* -cjf archive.tar2.bz2 maindir/*)
Olivier Pons

1
@OlivierPons แทนที่จะเป็น "under debian" หรืออาจจะใส่รุ่น tar ( tar --version); เดเบียนน่าจะส่งมอบเรือ tar พร้อมรุ่นที่แตกต่างกันหลายรุ่นตลอดหลายปีที่ผ่านมา
msouth

1
รุ่นของฉัน (1.29) ใช้ได้กับ--excludeก่อนหน้า-czfเท่านั้น
falsePockets

8

สำหรับการยกเว้นหลายไฟล์ให้ลอง

--exclude=/data/{sub1,sub2,sub3,sub4}

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

umount /data/{sub1,sub2,}

3
ฉันรัก curlies ฉันพบว่าผู้คนจำนวนมากไม่รู้เกี่ยวกับพวกเขาแม้จะมีประสบการณ์ unix เป็นเวลาหลายปี mv /very/very/very/very/long/path/to/a/file{,.bak}
msouth

5

ลิงค์นี้อาจมีประโยชน์ http://answers.google.com/answers/threadview/id/739467.html

สองความแตกต่างทันทีระหว่างสายที่ไม่ทำงานและเคล็ดลับในลิงค์:

  1. การแยกทั้งหมดมาหลังจากไดเรกทอรีระดับบนสุด
  2. ไม่สามารถมีช่องว่างใด ๆ หลังจากที่ผ่าน--excludeมา

ขอบคุณ คำตอบจาก-MAKความสนใจของฉันและจนถึงตอนนี้ฉันสามารถเห็นความแตกต่างต่อไปนี้ระหว่างบรรทัดที่ไม่ทำงานของฉันและต่อไปนี้: 1. การแยกทั้งหมดมาหลังจากไดเรกทอรีระดับบนสุด 2.ไม่สามารถมีช่องว่างใด ๆ --excludeหลังจากที่ผ่านมา ฉันจะทดสอบข้อมูลเชิงลึกเหล่านี้และรายงานกลับ +1 สำหรับตอนนี้
ateiob

@ateiob ถ้าคุณคิดออกคุณสามารถโพสต์คำตอบที่นี่หรือแก้ไขได้ไหม โดยทั่วไปเราไม่ต้องการคำตอบที่เป็นเพียงแค่ลิงก์อื่น ๆ
Michael Mrozek

@Michael Mrozek อย่างแน่นอน นี่คือสิ่งที่ฉันเขียนในความคิดเห็นของฉัน :)
ateiob

3

วิธีแก้ปัญหาอาจใช้การรวมกันของfind ... -pruneและtarเพื่อแยกไดเรกทอรีที่ระบุ

ใน Mac OS X --excludeตัวเลือกของ GNU tarดูเหมือนว่าจะทำงานได้ตามที่ควร

ในกรณีทดสอบต่อไปนี้ไดเรกทอรี/private/var/log/aslและ/private/var/log/DiagnosticMessagesจะถูกแยกออกจากไฟล์บีบอัดที่เก็บถาวรของ/private/var/logไดเรกทอรี

# all successfully tested in Bash shell on Mac OS X (using gnutar and gfind)

# sudo port install findutils  # for gfind from MacPorts

sudo gnutar -czf ~/Desktop/varlog.tar.gz /private/var/log --exclude "/private/var/log/asl" --exclude "/private/var/log/DiagnosticMessages"

sudo gnutar -czf ~/Desktop/varlog.tar.gz  --exclude "/private/var/log/asl" --exclude "/private/var/log/DiagnosticMessages" /private/var/log

set -f # disable file name globbing
sudo gnutar -czf ~/Desktop/varlog.tar.gz  --exclude "/private/var/log/asl" --exclude "/private/var/log/Diagnostic*" /private/var/log

# combining GNU find and tar (on Mac OS X)

sudo gfind /private/var/log -xdev -type d \( -name "asl" -o -name "DiagnosticMessages" \) -prune -o -print0 | 
   sudo gnutar --null --no-recursion -czf ~/Desktop/varlog.tar.gz --files-from -

# exclude even more dirs
sudo gfind /private/var/log -xdev -type d \( -name "asl" -o -name "[Dacfks]*" \) -prune -o -print0 | 
    sudo gnutar --null --no-recursion -czf ~/Desktop/varlog.tar.gz --files-from -


# testing the compressed archive

gnutar -C ~/Desktop -xzf ~/Desktop/varlog.tar.gz

sudo gfind /private/var/log ~/Desktop/private \( -iname DiagnosticMessages -or -iname asl \)

sudo rm -rf ~/Desktop/varlog.tar.gz ~/Desktop/private

ขอบคุณ +1 สำหรับคำแนะนำ ณ จุดนี้ฉันยังคงพยายามที่จะเข้าใจว่าทำไมคุณลักษณะ (และเป็นผู้ใหญ่) ที่มีการบันทึกไว้อย่างดีไม่ทำงานในสคริปต์ของฉันทำงานโดย cron ทุกคืน
ateiob

3

บางทีคุณสามารถลองคำสั่งด้วยตัวเลือกอื่น:

--wildcards

และตรวจสอบว่ามันทำงานได้ตามที่ตั้งใจไว้


ดูการอัปเดตของฉันด้านบน รูปแบบล่าสุดที่ทดลองใช้ (ไม่มีเครื่องหมายอัญประกาศเว้นวรรค) ฉันมีความคิดว่าทำไมไม่มี. +1 สำหรับแนวคิด
ateiob

3

ฉันใช้ mac และพบว่าการแยกไม่ทำงานยกเว้นว่าโฟลเดอร์ระดับบนสุดเป็นอาร์กิวเมนต์สุดท้าย

ตัวอย่างของคำสั่งการทำงาน:

tar czvf tar.tgz --exclude='Music' dir

FYI:

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3

กันไปกับ tar 1.27.1 ผ่าน Ubuntu 14.04
Greg Bell

3

ในกรณีของฉันมันไม่ได้แยกด้วยเหตุผลอื่น

เส้นทางแบบเต็มเทียบกับเส้นทางแบบสัมพัทธ์

ทั้งการแยกออกและไดเรกทอรีจะต้องใช้รูปแบบพา ธ เดียวกัน (เช่นทั้งเส้นทางแบบเต็มหรือเส้นทางแบบสัมพันธ์ทั้งสองเส้นทาง)

ตัวอย่าง:

tar -cvf ctms-db-sync.tar --exclude='/home/mine/tmp/ctms-db-sync/sql' ctms-db-sync

สิ่งนี้จะไม่ทำงานเนื่องจากการยกเว้นใช้เส้นทางแบบเต็มซึ่งเป็นเป้าหมายใช้เส้นทางแบบสัมพัทธ์

tar -cvf ctms-db-sync.tar --exclude='/home/mine/tmp/ctms-db-sync/sql' /home/mine/tmp/ctms-db-sync

วิธีนี้ใช้ได้ผลเพราะทั้งคู่ใช้เส้นทางแบบเต็ม

tar -cvf ctms-db-sync.tar --exclude='ctms-db-sync/sql' ctms-db-sync

สิ่งนี้ได้ผลเพราะทั้งคู่ใช้เส้นทางสัมพัทธ์



1

หมายเหตุเพิ่มเติมสำหรับคำตอบที่ยอดเยี่ยมของ R Perrin :

สมมติว่าคุณไม่ต้องการเก็บถาวร แต่เส้นทางสัมพัทธ์เช่น 'data' แทน '/ tmp / data' ในการยกเว้นเส้นทางสัมบูรณ์อาร์กิวเมนต์ tar ของคุณจะแตกต่างกันไปตามการใช้ tar (gnu tar vs. bsd tar) ที่คุณใช้:

$ for i in 0 1 2; do
    for j in 0 1 2; do 
      mkdir -p /tmp/data/sub$i/sub$j
      echo foo > /tmp/data/sub$i/sub$j/foo
    done
  done

$ find /tmp/data/
/tmp/data/
/tmp/data/sub2
/tmp/data/sub2/sub2
/tmp/data/sub2/sub2/foo
/tmp/data/sub2/sub1
/tmp/data/sub2/sub1/foo
/tmp/data/sub2/sub0
/tmp/data/sub2/sub0/foo
/tmp/data/sub1
/tmp/data/sub1/sub2
/tmp/data/sub1/sub2/foo
/tmp/data/sub1/sub1
/tmp/data/sub1/sub1/foo
/tmp/data/sub1/sub0
/tmp/data/sub1/sub0/foo
/tmp/data/sub0
/tmp/data/sub0/sub2
/tmp/data/sub0/sub2/foo
/tmp/data/sub0/sub1
/tmp/data/sub0/sub1/foo
/tmp/data/sub0/sub0
/tmp/data/sub0/sub0/foo

$ cd /tmp/data; tar -zvcf /tmp/_data.tar --exclude './sub[1-2]'
./
./sub0/
./sub0/sub2/
./sub0/sub2/foo
./sub0/sub1/
./sub0/sub1/foo
./sub0/sub0/
./sub0/sub0/foo

# ATTENTION: bsdtar's behaviour differs from traditional tar (without a leading '^')!
$ cd /tmp/data; bsdtar -zvcf /tmp/_data.tar --exclude './sub[1-2]' .
a .
a ./sub0
a ./sub0/sub0
a ./sub0/sub0/foo

# FIX: Use a regex by adding a leading '^' will cause bsdtar to match only parent files and folders.
$ cd /tmp/data; bsdtar -zvcf /tmp/_data.tar --exclude '^./sub[1-2]' .
# ALTERNATIVE: bsdtar -C /tmp/data -zvcf /tmp/_data.tar --exclude '^./sub[1-2]' .
a .
a ./sub0
a ./sub0/sub2
a ./sub0/sub1
a ./sub0/sub0
a ./sub0/sub0/foo
a ./sub0/sub1/foo
a ./sub0/sub2/foo

1

ตรวจพบเพียงแค่บน tar (GNU tar) 1.29

การโทรนี้จะไม่แยกออกจากไฟล์เก็บถาวรที่ระบุด้วย --exclude-from:

/bin/tar --files-from ${datafile} --exclude-from ${excludefile} -jcf ${backupfile}

การโทรนี้ทำงานอย่างกะทันหัน:

/bin/tar --exclude-from ${excludefile} --files-from ${datafile} -jcf ${backupfile}

ลำดับของพารามิเตอร์เป็นสิ่งสำคัญ!


0

ฉันลองชุดค่าผสมทุกประเภทรวมถึงคำตอบบางรายการที่ระบุไว้และไม่สามารถรับได้เพื่อยกเว้นไฟล์ที่ระบุ

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

ฉันไม่นี้โดยการสร้างที่เก็บแล้วเพิ่มไป :

tar -cvpf /path/to/mybackup.tar ./bin
tar rvf /path/to/mybackup.tar ./boot
tar rvf /path/to/mybackup.tar ./etc
tar rvf /path/to/mybackup.tar ./home
tar rvf /path/to/mybackup.tar ./lib
tar rvf /path/to/mybackup.tar ./sbin
tar rvf /path/to/mybackup.tar ./usr
tar rvf /path/to/mybackup.tar ./var

หมายเหตุเล็กน้อย:

  • ฉันใช้สัมพัทธ์แทนพา ธ สัมบูรณ์ (ซึ่งทำให้เกิดปัญหา) ด้วยการรันจากรูทของระบบไฟล์
  • คุณต้องสร้างไฟล์เก็บถาวรแบบธรรมดาtar(และไม่บีบอัด tar .tgz/ .tar.gz) คุณสามารถซิปได้ในภายหลังโดยใช้gzip mybackup.tar
  • ตรวจสอบให้แน่ใจว่าคุณไม่ได้จัดเก็บลงในโฟลเดอร์ใด ๆ ที่คุณกำลังรวมหรือคุณจะได้รับการสอบถามซ้ำ (การสำรองข้อมูลบางส่วนยังรวมอยู่ในการสำรองข้อมูลด้วย)
  • สังเกตเห็นความแตกต่างในคำสั่งแรก (สร้าง) จากคำสั่งอื่น (เพิ่ม)
  • คุณสามารถตรวจสอบว่าไฟล์ที่ถูกเพิ่มเข้ามากกว่าการสำรองข้อมูลเขียนทับ (เช่นหลังคำสั่งที่สอง) tar tvf mybackup.tarถ้าคุณมีความหวาดระแวงโดยใช้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.