Tìm tệp và chỉnh sửa chúng (có khoảng trắng)


110

Được rồi, vấn đề rất đơn giản ở đây. Tôi đang làm việc trên một mã sao lưu đơn giản. Nó hoạt động tốt trừ khi các tệp có khoảng trắng trong đó. Đây là cách tôi tìm các tệp và thêm chúng vào kho lưu trữ tar:

find . -type f | xargs tar -czvf backup.tar.gz 

Vấn đề là khi tệp có một khoảng trống trong tên vì tar nghĩ rằng đó là một thư mục. Về cơ bản, có cách nào tôi có thể thêm dấu ngoặc kép xung quanh kết quả từ tìm thấy không? Hoặc một cách khác để sửa lỗi này?


12
Cách tốt nhất để sử dụng find ... | xargs ...là sử dụng print0 / -0 tham số trên mỗi: find -print0 ... | xargs -0 .... Điều này sẽ khiến các tên tệp được phân tách bằng ký tự rỗng, có nghĩa là bạn có thể có khoảng trắng hoặc dòng mới hoặc những thứ kỳ lạ khác trong tên tệp của mình và nó vẫn hoạt động.
porges

8
Có một vấn đề với việc sử dụng xargs và tar theo cách này khi bạn có một số lượng lớn tệp, xargs sẽ liên tục gọi tar -c và điều đó sẽ tiếp tục ghi đè lên kho lưu trữ của bạn và kết quả là bạn sẽ không có tất cả các tệp như mong đợi . Xem giải thích chi tiết hơn nàycâu trả lời của tôi bên dưới.
Steve Kehlet

Câu trả lời:


217

Dùng cái này:

find . -type f -print0 | tar -czvf backup.tar.gz --null -T -

Nó sẽ:

  • xử lý các tệp bằng dấu cách, dòng mới, dấu gạch ngang ở đầu và các trò vui khác
  • xử lý số lượng tệp không giới hạn
  • sẽ không ghi đè nhiều lần backup.tar.gz của bạn như cách sử dụng tar -cwith xargssẽ làm khi bạn có một số lượng lớn tệp

Cũng thấy:


1
Bạn sẽ thực hiện điều này như thế nào nếu trước tiên bạn muốn xem qua sed một vài lần? ví dụ: tìm. -print0 | sed / backup / d | tar ....
Brad Parks

8
Lưu ý rằng nếu có nhiều điều kiện, bạn cần thêm dấu ngoặc đơn. Nếu không, chỉ -print0áp dụng cho biểu thức cuối cùng. Ví dụfind . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm

1
Để giải trí, đây là phiên bản Windows của điều này bằng cách sử dụng cygwin:c:\cygwin\bin\find . -regextype posix-egrep -regex '.*(sln^|vcxproj^|filters)$' -print0 | c:\cygwin\bin\tar -cvf MS_Projects.tar --null -T -
Jon

1
@Steve, bạn có thể vui lòng giải thích tùy chọn '-' là gì ở cuối lệnh tar. Tôi không thể tìm thấy nó trong trang người đàn ông của GNU tar.
shaffooo

Chắc chắn rồi, đó là một tham số -Tvà nó có nghĩa là đọc tên tệp từ đầu vào chuẩn: Nếu bạn đặt một dấu gạch ngang làm tên tệp cho `--files-from ', (tức là bạn chỉ định --files-from = - hoặc -T -), sau đó các tên tập tin được đọc từ đầu vào tiêu chuẩn
Steve Kehlet

14

Có thể có một cách khác để đạt được những gì bạn muốn. Về cơ bản,

  1. Sử dụng lệnh find để xuất đường dẫn đến bất kỳ tệp nào bạn đang tìm kiếm. Chuyển hướng stdout đến tên tệp bạn chọn.
  2. Sau đó, tar với tùy chọn -T cho phép nó lấy danh sách các vị trí tệp (vị trí mà bạn vừa tạo bằng find!)

    find . -name "*.whatever" > yourListOfFiles
    tar -cvf yourfile.tar -T yourListOfFiles
    

Có một câu trả lời ở đây về cách xử lý tên tập tin với dòng mới trong đó: superuser.com/a/513319/151261
tommy.carstensen

8

Thử chạy:

    find . -type f | xargs -d "\n" tar -czvf backup.tar.gz 

7

Tại sao không:

tar czvf backup.tar.gz *

Chắc chắn sẽ rất thông minh khi sử dụng find và then xargs, nhưng bạn đang làm điều đó một cách khó khăn.

Cập nhật: Porges đã nhận xét với một tùy chọn tìm kiếm mà tôi nghĩ là một câu trả lời tốt hơn câu trả lời của tôi hoặc câu trả lời khác: find -print0 ... | xargs -0 ....


Mã đầy đủ của tôi sẽ chỉ sao lưu các mục được sửa đổi trong ngày hôm qua. Vì đây là bản sao lưu hàng ngày, tôi không muốn có thông tin lặp lại để lưu trên kích thước tệp (tôi cũng có bản sao lưu đầy đủ 15 ngày một lần).
Caleb Kester

Để biến đây thành một câu hỏi SO hay hơn, tôi sẽ đặt câu hỏi về việc "sử dụng find, xargs và tar với nhau một cách đáng tin cậy". Tiêu đề và câu hỏi của bạn không thực sự chỉ rõ rằng bạn cần tìm và xargs, nhưng bạn vẫn làm.
Warren P

xargs ... tar c ...sẽ ghi đè lên tệp lưu trữ đầu tiên được tạo nếu danh sách tệp quá dài và xargssẽ thực thi tarlần thứ hai! Để tránh ghi đè, bạn có thể sử dụng xargs -xnhưng khi đó kho lưu trữ có thể không đầy đủ. Thay thế có thể là đầu tiên tar c ...và sau đó có thể lặp lại tar r .... (đóng góp của tôi đến độ tin cậy :)
pabouk

3

Nếu bạn có nhiều tệp hoặc thư mục và bạn muốn nén chúng thành *.gztệp độc lập, bạn có thể thực hiện việc này. Không bắt buộc-type f -atime

find -name "httpd-log*.txt" -type f -mtime +1 -exec tar -vzcf {}.gz {} \;

Điều này sẽ nén

httpd-log01.txt
httpd-log02.txt

đến

httpd-log01.txt.gz
httpd-log02.txt.gz

2

Tại sao không thử một cái gì đó như thế này: tar cvf scala.tar `find src -name *.scala`



2

Sẽ thêm nhận xét vào bài đăng của @Steve Kehlet nhưng cần 50 đại diện (RIP).

Đối với bất kỳ ai đã tìm thấy bài đăng này thông qua nhiều googling, tôi đã tìm thấy một cách để không chỉ tìm thấy các tệp cụ thể được cung cấp trong một phạm vi thời gian, mà còn KHÔNG bao gồm các đường dẫn tương đối HOẶC khoảng trắng sẽ gây ra lỗi tarring. (CẢM ƠN BẠN RẤT NHIỀU STEVE.)

find . -name "*.pdf" -type f -mtime 0 -printf "%f\0" | tar -czvf /dir/zip.tar.gz --null -T -
  1. . thư mục tương đối

  2. -name "*.pdf" tìm kiếm pdf (hoặc bất kỳ loại tệp nào)

  3. -type f loại cần tìm là một tệp

  4. -mtime 0 tìm kiếm các tệp được tạo trong 24 giờ qua

  5. -printf "%f\0"Thường xuyên -print0HOẶC -printf "%f"KHÔNG làm việc cho tôi. Từ trang người đàn ông:

Việc trích dẫn này được thực hiện theo cách tương tự như đối với GNU ls. Đây không phải là cơ chế trích dẫn giống như cơ chế được sử dụng cho -ls và -fls. Nếu bạn có thể quyết định định dạng nào sẽ sử dụng cho đầu ra của tìm kiếm thì thông thường tốt hơn là sử dụng '\ 0' làm dấu chấm cuối hơn là sử dụng dòng mới, vì tên tệp có thể chứa khoảng trắng và ký tự dòng mới.

  1. -czvf tạo kho lưu trữ, lọc kho lưu trữ thông qua gzip, liệt kê chi tiết các tệp được xử lý, tên lưu trữ

Chỉnh sửa 2019-08-14: Tôi muốn nói thêm rằng tôi cũng có thể sử dụng về cơ bản bằng cách sử dụng cùng một lệnh trong nhận xét của mình, chỉ sử dụng chính tar:

tar -czvf /archiveDir/test.tar.gz --newer-mtime=0 --ignore-failed-read *.pdf

Cần thiết --ignore-failed-readtrong trường hợp không có tệp PDF mới cho ngày hôm nay.


1

Giải pháp tốt nhất dường như là tạo danh sách tệp và sau đó lưu trữ tệp vì bạn có thể sử dụng các nguồn khác và làm điều gì đó khác với danh sách.

Ví dụ, điều này cho phép sử dụng danh sách để tính toán kích thước của các tệp đang được lưu trữ:

#!/bin/sh

backupFileName="backup-big-$(date +"%Y%m%d-%H%M")"
backupRoot="/var/www"
backupOutPath=""

archivePath=$backupOutPath$backupFileName.tar.gz
listOfFilesPath=$backupOutPath$backupFileName.filelist

#
# Make a list of files/directories to archive
#
echo "" > $listOfFilesPath
echo "${backupRoot}/uploads" >> $listOfFilesPath
echo "${backupRoot}/extra/user/data" >> $listOfFilesPath
find "${backupRoot}/drupal_root/sites/" -name "files" -type d >> $listOfFilesPath

#
# Size calculation
#
sizeForProgress=`
cat $listOfFilesPath | while read nextFile;do
    if [ ! -z "$nextFile" ]; then
        du -sb "$nextFile"
    fi
done | awk '{size+=$1} END {print size}'
`

#
# Archive with progress
#
## simple with dump of all files currently archived
#tar -czvf $archivePath -T $listOfFilesPath
## progress bar
sizeForShow=$(($sizeForProgress/1024/1024))
echo -e "\nRunning backup [source files are $sizeForShow MiB]\n"
tar -cPp -T $listOfFilesPath | pv -s $sizeForProgress | gzip > $archivePath

Một lớp lót cho điều này?
Robino
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.