Temukan file dan tar (dengan spasi)

110

Baiklah, masalah sangat sederhana di sini. Saya sedang mengerjakan kode cadangan sederhana. Ini berfungsi dengan baik kecuali jika file memiliki spasi di dalamnya. Beginilah cara saya menemukan file dan menambahkannya ke arsip tar:

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

Masalahnya adalah ketika file memiliki spasi di nama karena tar mengira itu folder. Pada dasarnya, apakah ada cara agar saya dapat menambahkan kutipan di sekitar hasil dari pencarian? Atau cara lain untuk memperbaikinya?

Caleb Kester
sumber
12
Cara terbaik untuk digunakan find ... | xargs ...adalah dengan menggunakan -print0 / -0 parameter pada setiap: find -print0 ... | xargs -0 .... Ini akan menyebabkan nama file dipisahkan oleh karakter null, yang berarti Anda dapat memiliki spasi atau baris baru atau hal aneh lainnya di nama file Anda dan itu akan tetap berfungsi.
Porges
8
Ada masalah dengan menggunakan xargs dan tar dengan cara ini ketika Anda memiliki banyak file, xargs akan berulang kali memanggil tar -c, dan itu akan terus menimpa arsip Anda, dan hasilnya adalah Anda tidak akan memiliki semua file yang Anda harapkan . Lihat penjelasan lebih detail ini dan jawaban saya di bawah ini.
Steve Kehlet

Jawaban:

217

Gunakan ini:

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

Itu akan:

  • menangani file dengan spasi, baris baru, tanda hubung di awal, dan kelucuan lainnya
  • menangani jumlah file yang tidak terbatas
  • tidak akan berulang kali menimpa backup.tar.gz Anda seperti menggunakan tar -cwith xargsakan dilakukan ketika Anda memiliki banyak file

Lihat juga:

Steve Kehlet
sumber
1
bagaimana Anda akan melakukan ini jika Anda ingin menyalurkan temuan Anda melalui sed beberapa kali terlebih dahulu? mis. temukan. -print0 | sed / backups / d | tar ....
Brad Parks
8
Perhatikan bahwa jika memiliki beberapa ketentuan, Anda perlu menambahkan tanda kurung. Jika tidak, hanya -print0berlaku untuk ekspresi terakhir. Misalnyafind . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm
1
Untuk bersenang-senang, inilah versi Windows yang menggunakan 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 bisakah Anda menjelaskan apa itu opsi '-' di akhir perintah tar. Saya tidak dapat menemukannya di halaman manual GNU tar.
shaffooo
Tentu, ini adalah parameter ke -T, dan itu berarti membaca nama file dari input standar: Jika Anda memberikan satu tanda hubung sebagai nama file untuk `--files-from ', (yaitu, Anda menentukan --files-from = - atau -T -), maka nama file dibaca dari input standar
Steve Kehlet
14

Mungkin ada cara lain untuk mencapai apa yang Anda inginkan. Pada dasarnya,

  1. Gunakan perintah find untuk menghasilkan jalur ke file apa pun yang Anda cari. Alihkan stdout ke nama file yang Anda pilih.
  2. Kemudian tar dengan opsi -T yang memungkinkannya untuk mengambil daftar lokasi file (yang baru saja Anda buat dengan find!)

    find . -name "*.whatever" > yourListOfFiles
    tar -cvf yourfile.tar -T yourListOfFiles
    
rawan kesalahan
sumber
Ada jawaban di sini tentang cara menangani nama file dengan baris baru di dalamnya: superuser.com/a/513319/151261
tommy.carstensen
8

Coba jalankan:

    find . -type f | xargs -d "\n" tar -czvf backup.tar.gz 
gsteff.dll
sumber
7

Kenapa tidak:

tar czvf backup.tar.gz *

Tentu pintar menggunakan find dan kemudian xargs, tetapi Anda melakukannya dengan cara yang sulit.

Pembaruan: Porges telah berkomentar dengan opsi temukan yang menurut saya merupakan jawaban yang lebih baik daripada jawaban saya, atau yang lain: find -print0 ... | xargs -0 ....

Warren P.
sumber
Kode lengkap saya hanya akan mencadangkan item yang diubah di hari sebelumnya. Karena ini adalah pencadangan harian, saya tidak ingin memiliki informasi berulang untuk menghemat ukuran file (saya juga memiliki cadangan penuh setiap 15 hari).
Caleb Kester
Untuk membuat ini menjadi pertanyaan SO yang lebih baik, saya akan mengajukan pertanyaan tentang "andal menggunakan find, xargs, dan tar bersama-sama". Judul dan pertanyaan Anda tidak benar-benar menentukan bahwa Anda perlu menemukan dan xargs, namun Anda melakukannya.
Warren P
xargs ... tar c ...akan menimpa arsip pertama yang dibuat jika daftar file terlalu panjang dan xargsakan dijalankan taruntuk kedua kalinya! Untuk menghindari penimpaan, Anda dapat menggunakan xargs -xtetapi arsipnya mungkin tidak lengkap. Alternatifnya bisa pertama tar c ...dan kemudian mungkin berulang kali tar r .... (kontribusi saya untuk keandalan :)
pabouk
3

Jika Anda memiliki banyak file atau direktori dan Anda ingin meng-zip-nya menjadi *.gzfile independen, Anda dapat melakukan ini. Pilihan-type f -atime

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

Ini akan memampatkan

httpd-log01.txt
httpd-log02.txt

untuk

httpd-log01.txt.gz
httpd-log02.txt.gz
Kalibur x
sumber
2

Mengapa tidak mencoba sesuatu seperti ini: tar cvf scala.tar `find src -name *.scala`

Frank Eggink
sumber
2

Solusi lain seperti yang terlihat di sini :

find var/log/ -iname "anaconda.*" -exec tar -cvzf file.tar.gz {} +
tommy.carstensen
sumber
2

Akan menambahkan komentar ke postingan @Steve Kehlet tetapi membutuhkan 50 rep (RIP).

Bagi siapa pun yang telah menemukan posting ini melalui banyak googling, saya menemukan cara untuk tidak hanya menemukan file tertentu yang diberikan rentang waktu, tetapi juga TIDAK menyertakan jalur relatif ATAU spasi yang akan menyebabkan kesalahan tarring. (TERIMA KASIH BANYAK STEVE.)

find . -name "*.pdf" -type f -mtime 0 -printf "%f\0" | tar -czvf /dir/zip.tar.gz --null -T -
  1. . direktori relatif

  2. -name "*.pdf" cari pdf (atau jenis file apa pun)

  3. -type f jenis yang dicari adalah file

  4. -mtime 0 cari file yang dibuat dalam 24 jam terakhir

  5. -printf "%f\0"Biasa -print0ATAU -printf "%f"TIDAK berhasil untuk saya. Dari halaman manual:

Kutipan ini dilakukan dengan cara yang sama seperti untuk GNU ls. Ini bukan mekanisme kutipan yang sama seperti yang digunakan untuk -ls dan -fls. Jika Anda dapat memutuskan format apa yang akan digunakan untuk keluaran find maka biasanya lebih baik menggunakan '\ 0' sebagai terminator daripada menggunakan baris baru, karena nama file dapat berisi spasi dan karakter baris baru.

  1. -czvf buat arsip, filter arsip melalui gzip, daftar file yang diproses secara verbal, nama arsip

Sunting 2019-08-14: Saya ingin menambahkan, bahwa saya juga dapat menggunakan pada dasarnya menggunakan perintah yang sama di komentar saya, hanya menggunakan tar itu sendiri:

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

Diperlukan --ignore-failed-readjika tidak ada PDF baru untuk hari ini.

pengguna3472383
sumber
1

Solusi terbaik tampaknya untuk membuat daftar file dan kemudian mengarsipkan file karena Anda dapat menggunakan sumber lain dan melakukan sesuatu yang lain dengan daftar tersebut.

Misalnya, ini memungkinkan penggunaan daftar untuk menghitung ukuran file yang diarsipkan:

#!/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
Nux
sumber
Satu baris untuk ini?
Robino