Trova i file e tarali (con spazi)


110

Va bene, così semplice problema qui. Sto lavorando a un semplice codice di backup. Funziona bene tranne se i file hanno spazi al loro interno. Ecco come trovo i file e li aggiungo a un archivio tar:

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

Il problema è quando il file ha uno spazio nel nome perché tar pensa che sia una cartella. Fondamentalmente c'è un modo per aggiungere virgolette intorno ai risultati di find? O un modo diverso per risolvere questo problema?


12
Il modo migliore per utilizzare find ... | xargs ...è quello di utilizzare il -print0 / -0 parametro su ogni: find -print0 ... | xargs -0 .... Questo farà sì che i nomi dei file siano separati da un carattere nullo, il che significa che puoi avere spazi o nuove righe o altre cose strane nei tuoi nomi di file e continuerà a funzionare.
porges

8
C'è un problema con l'uso di xargs e tar in questo modo quando hai un gran numero di file, xargs invocerà ripetutamente tar -c, e questo continuerà a sovrascrivere il tuo archivio, e il risultatoènon avrai tutti i file che ti aspetti . Vedi questa spiegazione più dettagliata e la mia risposta di seguito.
Steve Kehlet

Risposte:


217

Usa questo:

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

Lo farà:

  • gestire i file con spazi, nuove righe, trattini iniziali e altre cose divertenti
  • gestire un numero illimitato di file
  • non sovrascriverà ripetutamente il tuo backup.tar.gz come se usassi tar -ccon xargsquando hai un gran numero di file

Vedi anche:


1
come faresti se prima volessi convogliare la tua ricerca attraverso sed alcune volte? ad es. trova. -print0 | sed / backups / d | tar ....
Brad Parks

8
Nota che se hai più condizioni devi aggiungere parentesi. Altrimenti si -print0applica solo all'ultima espressione. Ad esempiofind . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm

1
Per divertimento, ecco una versione Windows di questo utilizzando 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 puoi spiegare cos'è l'opzione '-' alla fine del comando tar. Non riesco a trovarlo nella pagina man di GNU tar.
shaffooo

Certo, è un parametro per -T, e significa leggere i nomi dei file dallo standard input: Se dai un solo trattino come nome del file per `--files-from ', (cioè, specifichi o --files-from = - oppure -T -), i nomi dei file vengono letti dallo standard input
Steve Kehlet

14

Potrebbe esserci un altro modo per ottenere ciò che desideri. Fondamentalmente,

  1. Usa il comando find per visualizzare il percorso di qualsiasi file tu stia cercando. Reindirizza lo stdout a un nome di file a tua scelta.
  2. Quindi tar con l'opzione -T che gli consente di prendere un elenco di posizioni di file (quello che hai appena creato con find!)

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

C'è una risposta qui su come gestire i nomi di file con le nuove righe: superuser.com/a/513319/151261
tommy.carstensen

8

Prova a correre:

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

7

Perchè no:

tar czvf backup.tar.gz *

Certo è intelligente usare find e poi xargs, ma lo stai facendo nel modo più duro.

Aggiornamento: Porges ha commentato con un'opzione di ricerca che penso sia una risposta migliore della mia risposta, o dell'altra: find -print0 ... | xargs -0 ....


Il mio codice completo eseguirà il backup solo degli elementi modificati nell'ultimo giorno. Dal momento che è un backup giornaliero, non voglio avere informazioni ripetute per salvare sulla dimensione del file (ho anche un backup completo ogni 15 giorni).
Caleb Kester

Per rendere questa una domanda SO migliore, vorrei porre la domanda su "utilizzare in modo affidabile find, xargs e tar insieme". Il tuo titolo e la tua domanda non specificano realmente che hai bisogno di find e xargs, eppure lo fai.
Warren P

xargs ... tar c ...sovrascriverà il primo archivio creato se l'elenco dei file è troppo lungo e xargsverrà eseguito tarper la seconda volta! Per evitare la sovrascrittura si può usare xargs -xma poi l'archivio potrebbe essere incompleto. L'alternativa potrebbe essere prima tar c ...e poi possibilmente ripetutamente tar r .... (il mio contributo all'affidabilità :)
pabouk

3

Se hai più file o directory e desideri comprimerli in *.gzfile indipendenti , puoi farlo. Opzionale-type f -atime

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

Questo comprimerà

httpd-log01.txt
httpd-log02.txt

per

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

2

Perché non provare qualcosa di simile: tar cvf scala.tar `find src -name *.scala`


2

Un'altra soluzione come visto qui :

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

2

Aggiungerei un commento al post di @Steve Kehlet ma occorrono 50 ripetizioni (RIP).

Per chiunque abbia trovato questo post attraverso numerosi googling, ho trovato un modo non solo per trovare file specifici dato un intervallo di tempo, ma anche per NON includere i relativi percorsi O spazi bianchi che causerebbero errori di tarring. (GRAZIE MOLTO STEVE.)

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

  2. -name "*.pdf" cerca PDF (o qualsiasi tipo di file)

  3. -type f il tipo da cercare è un file

  4. -mtime 0 cerca i file creati nelle ultime 24 ore

  5. -printf "%f\0"-print0OR regolare -printf "%f"NON ha funzionato per me. Dalle pagine man:

Questa citazione viene eseguita nello stesso modo di GNU ls. Questo non è lo stesso meccanismo di citazione di quello usato per -ls e -fls. Se sei in grado di decidere quale formato utilizzare per l'output di find, è normalmente meglio usare "\ 0" come terminatore piuttosto che utilizzare newline, poiché i nomi dei file possono contenere spazi bianchi e caratteri di nuova riga.

  1. -czvf crea archivio, filtra l'archivio tramite gzip, elenca in modo dettagliato i file elaborati, nome dell'archivio

Modifica 14-08-2019: vorrei aggiungere che sono stato anche in grado di utilizzare essenzialmente lo stesso comando nel mio commento, semplicemente usando tar stesso:

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

Necessario --ignore-failed-readnel caso in cui non ci fossero nuovi PDF per oggi.


1

La soluzione migliore sembra essere quella di creare un elenco di file e quindi archiviare i file perché è possibile utilizzare altre fonti e fare qualcos'altro con l'elenco.

Ad esempio, ciò consente di utilizzare l'elenco per calcolare la dimensione dei file archiviati:

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

Una linea per questo?
Robino
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.