ค้นหาไฟล์และทาร์ต (ด้วยช่องว่าง)


110

เอาล่ะปัญหาง่ายๆตรงนี้ ฉันกำลังทำงานกับรหัสสำรองง่ายๆ ทำงานได้ดียกเว้นว่าไฟล์มีช่องว่างอยู่ นี่คือวิธีที่ฉันค้นหาไฟล์และเพิ่มลงในไฟล์เก็บถาวร tar:

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

ปัญหาคือเมื่อไฟล์มีช่องว่างในชื่อเนื่องจาก tar คิดว่าเป็นโฟลเดอร์ โดยพื้นฐานแล้วฉันสามารถเพิ่มเครื่องหมายคำพูดรอบ ๆ ผลลัพธ์จากการค้นหาได้หรือไม่? หรือวิธีอื่นในการแก้ไขปัญหานี้?


12
วิธีที่ดีที่สุดที่จะใช้find ... | xargs ...คือการใช้ / -0 พารามิเตอร์ -print0 find -print0 ... | xargs -0 ...ในแต่ละ: สิ่งนี้จะทำให้ชื่อไฟล์ถูกคั่นด้วยอักขระ null ซึ่งหมายความว่าคุณสามารถมีช่องว่างหรือขึ้นบรรทัดใหม่หรือสิ่งแปลก ๆ อื่น ๆ ในชื่อไฟล์ของคุณและจะยังใช้งานได้
porges

8
มีปัญหาในการใช้ xargs และ tar ด้วยวิธีนี้เมื่อคุณมีไฟล์จำนวนมาก xargs จะเรียกใช้ tar -c ซ้ำ ๆ และจะเขียนทับไฟล์เก็บถาวรของคุณและผลลัพธ์ก็คือคุณจะไม่มีไฟล์ทั้งหมดที่คุณคาดหวัง . ดูคำอธิบายโดยละเอียดเพิ่มเติมและคำตอบของฉันด้านล่าง
Steve Kehlet

คำตอบ:


217

ใช้สิ่งนี้:

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

มันจะ:

  • จัดการกับไฟล์ที่มีช่องว่างบรรทัดใหม่ขีดกลางนำหน้าและความสนุกสนานอื่น ๆ
  • จัดการไฟล์ได้ไม่ จำกัด จำนวน
  • จะไม่เขียนทับ backup.tar.gz ซ้ำ ๆ เหมือนการใช้tar -cกับxargsจะทำเมื่อคุณมีไฟล์จำนวนมาก

ดูเพิ่มเติมที่:


1
คุณจะทำสิ่งนี้ได้อย่างไรถ้าคุณต้องการที่จะนำสิ่งที่คุณพบผ่าน sed สองสามครั้งก่อน? เช่นหา. -print0 | sed / การสำรองข้อมูล / d | tar ....
Brad Parks

8
โปรดทราบว่าหากมีหลายเงื่อนไขคุณต้องเพิ่มวงเล็บ มิฉะนั้น-print0จะใช้กับนิพจน์สุดท้ายเท่านั้น เช่นfind . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm

1
เพื่อความสนุกสนานนี่คือเวอร์ชัน Windows ที่ใช้ 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 คุณช่วยอธิบายตัวเลือก '-' ที่ท้ายคำสั่ง tar ได้ไหม หาไม่เจอใน man page ของ GNU tar
shaffooo

แน่นอนมันเป็นพารามิเตอร์-Tและหมายถึงอ่านชื่อไฟล์จากอินพุตมาตรฐาน: หากคุณให้ขีดเดียวเป็นชื่อไฟล์สำหรับ `--files-from '(กล่าวคือคุณระบุ --files-from = - หรือ -T -) จากนั้นชื่อไฟล์จะถูกอ่านจากอินพุตมาตรฐาน
Steve Kehlet

14

อาจมีวิธีอื่นในการบรรลุสิ่งที่คุณต้องการ โดยพื้นฐานแล้ว

  1. ใช้คำสั่งfindเพื่อส่งออกพา ธ ไปยังไฟล์ที่คุณต้องการ เปลี่ยนเส้นทางstdoutไปยังชื่อไฟล์ที่คุณเลือก
  2. จากนั้นทาร์ด้วยอ็อพชัน -T ซึ่งอนุญาตให้ใช้รายการตำแหน่งไฟล์ (ที่คุณเพิ่งสร้างด้วยการค้นหา!)

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

มีคำตอบเกี่ยวกับวิธีจัดการชื่อไฟล์ที่มีบรรทัดใหม่อยู่ที่นี่: superuser.com/a/513319/151261
tommy.carstensen


7

ทำไมจะไม่ล่ะ:

tar czvf backup.tar.gz *

แน่นอนว่ามันฉลาดที่จะใช้การค้นหาและ xargs แต่คุณกำลังทำมันเป็นวิธีที่ยาก

อัปเดต: Porges ได้แสดงความคิดเห็นพร้อมกับตัวเลือกการค้นหาที่ฉันคิดว่าเป็นคำตอบที่ดีกว่าคำตอบของฉันหรืออีกข้อหนึ่ง: find -print0 ... | xargs -0 ....


รหัสเต็มของฉันจะสำรองเฉพาะรายการที่แก้ไขในวันที่ผ่านมา เนื่องจากมีการสำรองข้อมูลทุกวันฉันจึงไม่ต้องการให้มีข้อมูลซ้ำเพื่อบันทึกขนาดไฟล์ (ฉันมีการสำรองข้อมูลเต็มทุก 15 วัน)
Caleb Kester

เพื่อให้เป็นคำถาม SO ที่ดีขึ้นฉันจะถามคำถามเกี่ยวกับ "การใช้ find, xargs และ tar ร่วมกันอย่างน่าเชื่อถือ" ชื่อและคำถามของคุณไม่ได้ระบุว่าคุณต้องการค้นหาและ xargs แต่คุณก็ยังทำ
Warren P

xargs ... tar c ...จะเขียนทับไฟล์เก็บถาวรแรกที่สร้างขึ้นหากรายการไฟล์ยาวเกินไปและxargsจะดำเนินการtarเป็นครั้งที่สอง! เพื่อหลีกเลี่ยงการเขียนทับคุณสามารถใช้xargs -xแต่ที่เก็บถาวรอาจไม่สมบูรณ์ ทางเลือกที่อาจจะเป็นครั้งแรกและจากนั้นอาจจะซ้ำแล้วซ้ำอีกtar c ... tar r ...(ผลงานของฉันต่อความน่าเชื่อถือ :)
pabouk

3

หากคุณมีไฟล์หรือไดเร็กทอรีหลายไฟล์และต้องการ zip เป็น*.gzไฟล์อิสระคุณสามารถทำได้ ไม่จำเป็น-type f -atime

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

ซึ่งจะบีบอัด

httpd-log01.txt
httpd-log02.txt

ถึง

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



2

จะเพิ่มความคิดเห็นในโพสต์ @Steve Kehletแต่ต้องการ 50 ตัวแทน (RIP)

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

find . -name "*.pdf" -type f -mtime 0 -printf "%f\0" | tar -czvf /dir/zip.tar.gz --null -T -
  1. . ไดเร็กทอรีสัมพัทธ์

  2. -name "*.pdf" มองหาไฟล์ PDF (หรือไฟล์ประเภทใดก็ได้)

  3. -type f ประเภทที่ต้องการค้นหาคือไฟล์

  4. -mtime 0 มองหาไฟล์ที่สร้างขึ้นใน 24 ชั่วโมงที่ผ่านมา

  5. -printf "%f\0"ปกติ-print0หรือ-printf "%f"ไม่ได้ผลสำหรับฉัน จากหน้าคน:

การอ้างอิงนี้ดำเนินการในลักษณะเดียวกับ GNU ls นี่ไม่ใช่กลไกการอ้างอิงเดียวกับกลไกที่ใช้สำหรับ -ls และ -fls หากคุณสามารถตัดสินใจได้ว่าจะใช้รูปแบบใดสำหรับผลลัพธ์ของการค้นหาโดยปกติแล้วการใช้ '\ 0' เป็นตัวยุติจะดีกว่าการใช้การขึ้นบรรทัดใหม่เนื่องจากชื่อไฟล์สามารถมีช่องว่างและอักขระขึ้นบรรทัดใหม่ได้

  1. -czvf สร้างไฟล์เก็บถาวรกรองไฟล์เก็บถาวรผ่าน gzip ไฟล์รายการที่ประมวลผลอย่างละเอียดชื่อไฟล์เก็บถาวร

แก้ไข 2019-08-14: ฉันต้องการเพิ่มว่าฉันยังสามารถใช้คำสั่งเดียวกันนี้ในความคิดเห็นของฉันได้โดยใช้ tar เอง:

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

จำเป็น--ignore-failed-readในกรณีที่ไม่มี PDF ใหม่สำหรับวันนี้


1

ทางออกที่ดีที่สุดคือการสร้างรายการไฟล์จากนั้นจึงเก็บไฟล์เนื่องจากคุณสามารถใช้แหล่งข้อมูลอื่นและทำอย่างอื่นกับรายการได้

ตัวอย่างเช่นสิ่งนี้อนุญาตให้ใช้รายการเพื่อคำนวณขนาดของไฟล์ที่ถูกเก็บถาวร:

#!/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

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