Rechercher des fichiers et les tarer (avec des espaces)

110

Très bien, problème si simple ici. Je travaille sur un simple code de sauvegarde. Cela fonctionne bien sauf si les fichiers contiennent des espaces. Voici comment je trouve des fichiers et les ajoute à une archive tar:

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

Le problème est lorsque le fichier a un espace dans le nom car tar pense que c'est un dossier. En gros, existe-t-il un moyen d'ajouter des citations autour des résultats de find? Ou une autre façon de résoudre ce problème?

Caleb Kester
la source
12
La meilleure façon d'utiliser find ... | xargs ...est d'utiliser le -print0 / -0 paramètre sur chaque: find -print0 ... | xargs -0 .... Cela entraînera la séparation des noms de fichiers par un caractère nul, ce qui signifie que vous pouvez avoir des espaces ou des retours à la ligne ou d'autres choses étranges dans vos noms de fichiers et cela fonctionnera toujours.
porges
8
Il y a un problème avec l'utilisation de xargs et tar de cette façon lorsque vous avez un grand nombre de fichiers, xargs appellera à plusieurs reprises tar -c, et cela continuera d'écraser votre archive, et le résultat est que vous n'aurez pas tous les fichiers que vous attendez . Voir cette explication plus détaillée et ma réponse ci-dessous.
Steve Kehlet

Réponses:

217

Utilisez ceci:

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

Ce sera:

  • gérer les fichiers avec des espaces, des retours à la ligne, des tirets en tête et d'autres aspects amusants
  • gérer un nombre illimité de fichiers
  • ne remplacera pas à plusieurs reprises votre backup.tar.gz comme avec tar -cavec le xargsfera lorsque vous avez un grand nombre de fichiers

Regarde aussi:

Steve Kehlet
la source
1
Comment feriez-vous cela si vous vouliez d'abord diffuser votre découverte à travers sed plusieurs fois? par exemple trouver. -print0 | sed / sauvegardes / d | tar ....
Brad Parks
8
Notez que si vous avez plusieurs conditions, vous devez ajouter des parenthèses. Sinon, -print0s'applique uniquement à la dernière expression. Par exemplefind . \( -type f -o -name '*.c' \) -print0 | ...
nimrodm
1
Pour le plaisir, voici une version Windows de ceci en utilisant 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 pouvez-vous expliquer ce qu'est l'option '-' à la fin de la commande tar. Je ne peux pas le trouver dans la page de manuel de GNU tar.
shaffooo
Bien sûr, c'est un paramètre à -T, et cela signifie lire les noms de fichiers à partir de l'entrée standard: Si vous donnez un seul tiret comme nom de fichier pour `--files-from ', (c'est-à-dire que vous spécifiez soit --files-from = - ou -T -), puis les noms de fichiers sont lus à partir de l'entrée standard
Steve Kehlet
14

Il pourrait y avoir une autre façon de réaliser ce que vous voulez. Fondamentalement,

  1. Utilisez la commande find pour afficher le chemin vers les fichiers que vous recherchez. Redirigez stdout vers un nom de fichier de votre choix.
  2. Puis tar avec l'option -T qui lui permet de prendre une liste d'emplacements de fichiers (celui que vous venez de créer avec find!)

    find . -name "*.whatever" > yourListOfFiles
    tar -cvf yourfile.tar -T yourListOfFiles
    
source d'erreur
la source
Il y a une réponse ici sur la façon de gérer les noms de fichiers avec des nouvelles lignes: superuser.com/a/513319/151261
tommy.carstensen
8

Essayez de courir:

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

Pourquoi pas:

tar czvf backup.tar.gz *

Bien sûr, il est intelligent d'utiliser find puis xargs, mais vous le faites à la dure.

Mise à jour: Porges a commenté avec une option de recherche qui, à mon avis, est une meilleure réponse que ma réponse, ou l'autre: find -print0 ... | xargs -0 ....

Warren P
la source
Mon code complet ne sauvegardera que les éléments modifiés au cours de la dernière journée. Puisqu'il s'agit d'une sauvegarde quotidienne, je ne veux pas avoir d'informations répétées pour enregistrer la taille du fichier (j'ai également une sauvegarde complète tous les 15 jours).
Caleb Kester
Pour en faire une meilleure question SO, je poserais la question sur "l'utilisation fiable de find, xargs et tar ensemble". Votre titre et votre question ne spécifient pas vraiment que vous avez besoin de trouver et de xargs, et pourtant vous le faites.
Warren P
xargs ... tar c ...écrasera la première archive créée si la liste des fichiers est trop longue et xargss'exécutera tarune deuxième fois! Pour éviter l'écrasement, vous pouvez utiliser, xargs -xmais l'archive pourrait être incomplète. Une alternative pourrait être d'abord tar c ..., puis éventuellement à plusieurs reprises tar r .... (ma contribution à la fiabilité :)
pabouk
3

Si vous avez plusieurs fichiers ou répertoires et que vous souhaitez les compresser dans un *.gzfichier indépendant , vous pouvez le faire. Optionnel-type f -atime

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

Cela va compresser

httpd-log01.txt
httpd-log02.txt

à

httpd-log01.txt.gz
httpd-log02.txt.gz
Kalibur x
la source
2

Pourquoi ne pas essayer quelque chose comme ça: tar cvf scala.tar `find src -name *.scala`

Frank Eggink
la source
2

Une autre solution comme vu ici :

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

Ajouter un commentaire à la publication de @Steve Kehlet mais nécessiterait 50 représentants (RIP).

Pour tous ceux qui ont trouvé ce message grâce à de nombreux googlages, j'ai trouvé un moyen non seulement de trouver des fichiers spécifiques selon une plage de temps, mais également de NE PAS inclure les chemins relatifs OU les espaces blancs qui provoqueraient des erreurs de goudronnage. (MERCI BEAUCOUP STEVE.)

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

  2. -name "*.pdf" recherchez des fichiers PDF (ou n'importe quel type de fichier)

  3. -type f le type à rechercher est un fichier

  4. -mtime 0 rechercher les fichiers créés au cours des dernières 24 heures

  5. -printf "%f\0"Régulier -print0OU -printf "%f"ne fonctionnait pas pour moi. Depuis les pages de manuel:

Cette citation est effectuée de la même manière que pour les GNU ls. Ce n'est pas le même mécanisme de guillemets que celui utilisé pour -ls et -fls. Si vous êtes en mesure de décider du format à utiliser pour la sortie de la recherche, il est normalement préférable d'utiliser '\ 0' comme terminateur que d'utiliser une nouvelle ligne, car les noms de fichiers peuvent contenir des espaces et des caractères de nouvelle ligne.

  1. -czvf créer une archive, filtrer l'archive via gzip, lister les fichiers traités de manière verbale, nom de l'archive

Edit 2019-08-14: Je voudrais ajouter que j'ai également pu utiliser essentiellement la même commande dans mon commentaire, en utilisant simplement tar lui-même:

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

Nécessaire --ignore-failed-readau cas où il n'y aurait pas de nouveaux PDF pour aujourd'hui.

utilisateur3472383
la source
1

La meilleure solution semble être de créer une liste de fichiers puis d'archiver les fichiers car vous pouvez utiliser d'autres sources et faire autre chose avec la liste.

Par exemple, cela permet d'utiliser la liste pour calculer la taille des fichiers archivés:

#!/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
la source
Une doublure pour ça?
Robino