tar --exclude không loại trừ. Tại sao?


71

Tôi có dòng rất đơn giản này trong một tập lệnh bash thực thi thành công (nghĩa là tạo _data.tartệp), ngoại trừ việc nó không loại trừ các thư mục con mà nó được thông báo loại trừ thông qua --excludetùy chọn:

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

Thay vào đó, nó tạo ra một _data.tartệp chứa mọi thứ bên dưới / dữ liệu, bao gồm các tệp trong thư mục con tôi muốn loại trừ.

Bất cứ ý tưởng tại sao? và làm thế nào để khắc phục điều này?

Cập nhật Tôi đã triển khai các quan sát của mình dựa trên liên kết được cung cấp trong câu trả lời đầu tiên bên dưới (thư mục cấp cao nhất trước, không có khoảng trắng sau khi loại trừ cuối cùng):

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

Nhưng điều đó không giúp được gì. Tất cả các thư mục con "loại trừ" đều có trong _data.tartệp kết quả .

Điều này thật khó hiểu. Cho dù đây là lỗi trong tar hiện tại (GNU tar 1.23, trên CentOS 6.2, Linux 2.6.32) hay "độ nhạy cực cao" của tar đối với khoảng trắng và các lỗi chính tả dễ bỏ sót khác, tôi coi đây là lỗi. Để bây giờ.

Điều này thật kinh khủng : Tôi đã thử cái nhìn sâu sắc được đề xuất bên dưới (không có dấu vết /*) và nó vẫn không hoạt động trong kịch bản sản xuất:

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

Tôi không thể thấy bất kỳ sự khác biệt nào giữa những gì tôi đã thử và những gì @Richard Perrin đã thử, ngoại trừ dấu ngoặc kép và 2 khoảng trắng thay vì 1. Tôi sẽ thử điều này (phải đợi kịch bản hàng đêm chạy khi thư mục được sao lưu lên là rất lớn) và báo cáo lại.

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

Tôi bắt đầu nghĩ rằng tất cả những tar --excludesự nhạy cảm này không phải là tar mà là một cái gì đó trong môi trường của tôi, nhưng sau đó nó có thể là gì?

Nó đã làm việc! Biến thể cuối cùng đã thử (không có dấu ngoặc đơn và dấu cách đơn thay vì không gian kép giữa các --exclude) được thử nghiệm. Lạ nhưng chấp nhận.

Không thể tin được! Nó chỉ ra rằng một phiên bản cũ hơn tar(1.15.1) sẽ chỉ loại trừ nếu thư mục cấp cao nhất là cuối cùng trên dòng lệnh. Điều này hoàn toàn ngược lại với cách yêu cầu phiên bản 1.23. FYI.

Câu trả lời:


50

Nếu bạn muốn loại trừ toàn bộ một thư mục, mẫu của bạn phải khớp với thư mục đó, không phải các tệp trong đó. Sử dụng --exclude=/data/sub1thay vì--exclude='/data/sub1/*'

Hãy cẩn thận với việc trích dẫn các mẫu để bảo vệ chúng khỏi sự mở rộng vỏ.

Xem ví dụ này, với sự cố trong lệnh gọi cuối cùng:

$ 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

Cảm ơn câu trả lời rất tập trung và rõ ràng. Về điểm đầu tiên của bạn, tôi đã cố gắng làm theo các mẹo trong chủ đề LQ này . Tôi không chắc chắn những gì tôi đã bỏ lỡ, nhưng bây giờ tôi đọc điểm thứ 2 của bạn, nó rất có thể là một vấn đề đường dẫn tuyệt đối so với tương đối. Tôi sẽ thử điều đó và báo cáo lại. +1 bây giờ.
ateiob

Một điều tôi nhận thấy là --exclude b(không gian thay vì dấu bằng) vs --exclude=b. Điều này có làm nên sự khác biệt? (không nên IMHO)
ateiob

1
Dấu bằng có thể là điều cần thiết để tránh sự mở rộng vỏ của các mẫu không được trích dẫn. Nếu bạn có một khoảng trắng thay vào đó, thì mẫu không được trích dẫn có thể được mở rộng bằng shell thành một đối số - bao gồm duy nhất và các phần mở rộng còn lại cung cấp dưới dạng tệp để thêm vào tệp tar. Tất cả các ví dụ của bạn ở trên đều có '=' - nếu tập lệnh không và thiếu dấu ngoặc đơn, thì đó có thể là nguồn gốc của vấn đề của bạn.
R Perrin

ĐỒNG Ý. Tôi đã kiểm tra ví dụ của bạn trên hộp của tôi và nó hoạt động, thậm chí với nhiều --exclude=trên cùng một dòng. Vì vậy, sự khác biệt phải là ngu ngốc /*mà tôi đã thêm vào mỗi thư mục con. Tôi sẽ kiểm tra tối nay trong kịch bản sản xuất và báo cáo lại. +1 khác.
ateiob

Đối với tôi, câu trả lời từ @carlo là vấn đề cụ thể - ngu ngốc không thể lấy - ngoại trừ là lựa chọn cuối cùng trên dòng lệnh - rõ ràng gây ra nhiều vấn đề đau đầu. Cảm ơn tất cả.
psychboom

32

Có thể là phiên bản taryêu cầu của bạn yêu cầu các --excludetùy chọn phải được đặt ở đầu tarlệnh.

Xem: https://stackoverflow.com/q/984204

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

Xem: http://mandrivausers.org/index.php?/topic/8585-multipl-exclude-in-tar/

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

Thay thế:

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

Một tarmẹo lệnh khác là từ đây :

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

Xem cập nhật của tôi ở trên. Biến thể cuối cùng đã thử (không có dấu ngoặc kép, không gian đơn) hoạt động. Tôi không biết tại sao. +1 cho câu trả lời hay suy nghĩ.
ateiob

FYI, theo debian, Nếu tôi không chính xác bộ lọc, như thế --exclude=mydir/*thì nó không hoạt động (sử dụng tar --exclude=maindir/mydir/* -cjf archive.tar2.bz2 maindir/*).
Olivier Pons

1
@OlivierPons thay vì "theo debian", hoặc có lẽ với nó, đặt phiên bản tar ( tar --version); debian có lẽ sẽ xuất xưởng với nhiều phiên bản tar khác nhau trong những năm qua.
msouth

1
Phiên bản của tôi (1.29) chỉ hoạt động với --excludetrước đó -czf.
falsePockets

8

Để loại trừ nhiều tệp, hãy thử

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

Điều này sẽ tiết kiệm một số mã và đau đầu. Đây là một giải pháp toàn cầu, cho tất cả các loại chương trình / tùy chọn. Nếu bạn cũng muốn bao gồm thư mục mẹ trong lựa chọn của mình (trong trường hợp này là dữ liệu), bạn phải bao gồm dấu phẩy. Ví dụ:

umount /data/{sub1,sub2,}

3
Tôi yêu curlies. Tôi thấy rằng rất nhiều người không biết về họ, ngay cả với nhiều năm kinh nghiệm. mv /very/very/very/very/long/path/to/a/file{,.bak}
msouth

5

Liên kết này có thể hữu ích. http://answers.google.com/answers/threadview/id/739467.html

Hai sự khác biệt ngay lập tức giữa dòng không hoạt động và một số mẹo trong liên kết:

  1. Tất cả các loại trừ đến sau thư mục cấp cao nhất.
  2. Không thể có bất kỳ khoảng trống nào sau cùng --exclude.

Cảm ơn. Câu trả lời bằng cách -MAKthu hút sự chú ý của tôi và cho đến nay tôi đã có thể phát hiện ra những khác biệt sau đây giữa dòng không hoạt động của tôi và sau: 1. Tất cả các loại trừ đều xuất hiện sau thư mục cấp cao nhất. 2. Không thể có bất kỳ khoảng trống nào sau lần cuối --exclude. Tôi sẽ kiểm tra những hiểu biết này và báo cáo lại. +1 bây giờ.
ateiob

@ateiob Nếu bạn tìm ra nó, bạn có thể gửi câu trả lời ở đây hoặc chỉnh sửa câu hỏi này không? Chúng tôi thường không muốn có câu trả lời mà chỉ là các liên kết ở nơi khác
Michael Mrozek

@Michael Mrozek Hoàn toàn. Đây chính xác là những gì tôi đã viết trong bình luận của tôi. :)
ateiob

3

Một cách giải quyết khác có thể là sử dụng kết hợp find ... -prunetarloại trừ các thư mục được chỉ định.

Trên Mac OS X, --excludetùy chọn GNU tardường như hoạt động như bình thường.

Trong trường hợp kiểm tra sau đây, các thư mục /private/var/log/asl/private/var/log/DiagnosticMessagessẽ được loại trừ khỏi kho lưu trữ nén của /private/var/logthư mục.

# 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

Cảm ơn +1 cho đề xuất. Tại thời điểm này, tôi vẫn đang cố gắng để hiểu tại sao một tính năng được ghi chép tốt (và trưởng thành) không hoạt động trong kịch bản của tôi, được điều hành hàng đêm bởi cron.
ateiob

3

Có lẽ bạn có thể thử lệnh với tùy chọn khác:

--wildcards

Và kiểm tra xem nó có chạy như dự định không.


Xem cập nhật của tôi ở trên. Biến thể cuối cùng đã thử (không có dấu ngoặc kép, không gian đơn) hoạt động. Tôi không biết tại sao. +1 cho ý tưởng.
ateiob

3

Tôi đang sử dụng máy Mac và thấy rằng loại trừ không hoạt động trừ khi thư mục cấp cao nhất là đối số cuối cùng

ví dụ về lệnh làm việc:

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

Tài chính

$: tar --version
bsdtar 2.8.3 - libarchive 2.8.3

Tương tự với tar 1.27.1 qua Ubuntu 14.04.
Greg Bell

3

Trong trường hợp của tôi, nó đã không loại trừ vì một lý do khác.

Đường dẫn đầy đủ so với đường dẫn tương đối.

Cả loại trừ và thư mục phải sử dụng cùng một định dạng đường dẫn (nghĩa là cả đường dẫn đầy đủ hoặc cả hai đường dẫn tương đối)

Thí dụ:

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

Điều này sẽ không hoạt động vì loại trừ sử dụng đường dẫn đầy đủ trong khi mục tiêu sử dụng đường dẫn tương đối

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

Điều này hoạt động vì cả hai sử dụng đường dẫn đầy đủ

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

Điều này hoạt động vì cả hai sử dụng đường dẫn tương đối



1

Ghi chú bổ sung cho câu trả lời xuất sắc của R Perrin :

Giả sử bạn không muốn lưu trữ các đường dẫn tuyệt đối nhưng tương đối, ví dụ: 'dữ liệu' thay vì '/ tmp / dữ liệu'. Để loại trừ các đường dẫn tuyệt đối, các đối số tar của bạn sẽ khác nhau dựa trên cách triển khai tar (gnu tar so với bsd tar) mà bạn sử dụng:

$ 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

Vừa được phát hiện trên tar (GNU tar) 1.29

Cuộc gọi này không loại trừ khỏi các tệp lưu trữ được chỉ định bằng --exclude-from:

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

Cuộc gọi này hoạt động đồng thời:

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

Thứ tự của các tham số là quan trọng!


0

Tôi đã thử tất cả các loại kết hợp bao gồm một vài câu trả lời được liệt kê và không thể lấy nó để loại trừ các tệp được liệt kê.

Vì vậy, chán ngấy việc theo đuổi câu trả lời cho những gì có nghĩa là một công việc năm phút tôi đã làm ngược lại: tạo ra một kho lưu trữ các thư mục tôi muốn đưa vào.

Tôi đã làm điều này bằng cách tạo một kho lưu trữ sau đó thêm vào nó :

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

Một vài lưu ý:

  • Tôi đã sử dụng tương đối thay vì các đường dẫn tuyệt đối (cũng gây rắc rối) bằng cách chạy từ thư mục gốc của hệ thống tập tin.
  • Bạn phải tạo một kho lưu trữ đơn giản tar(và không được nén tar .tgz/ .tar.gz) - bạn có thể nén nó sau bằng cách sử dụnggzip mybackup.tar
  • Hãy chắc chắn rằng bạn không đặt kho lưu trữ vào bất kỳ thư mục nào bạn đang đưa vào hoặc bạn sẽ nhận được một số đệ quy (một bản sao lưu một phần cũng được bao gồm trong chính bản sao lưu).
  • Lưu ý sự khác biệt trong lệnh đầu tiên (tạo) từ các lệnh khác (thêm).
  • Bạn có thể kiểm tra xem các tập tin đang được thêm vào chứ không phải là bản sao lưu được ghi đè (ví dụ: sau lệnh thứ hai) nếu bạn bị hoang tưởng bằng cách sử dụng tar tvf mybackup.tar.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.