fichiers tar uniquement, pas de répertoires

16

Je peux probablement écrire un script shell pour trouver des fichiers uniquement, puis passer la liste à tar, mais je me demande s'il existe déjà une fonctionnalité intégrée dans tar qui permet de faire exactement cela, dans une seule ligne de commande?

Par exemple, j'ai trouvé le --no-recursioncommutateur, mais quand je le fais:

tar --no-recursion -cvf mydir.tar mydir

Il archive uniquement les noms des entrées du répertoire (y compris les sous-répertoires!), Mais il n'archive aucun fichier.

J'ai aussi essayé:

 tar --no-recursion -cvf mydir.tar mydir/*

Mais s'il archive uniquement les fichiers, il archive également les noms des sous-répertoires.

Existe-t-il un moyen de dire uniquement aux fichiers tar, pas de répertoires?

ateiob
la source
5
Juste pour clarifier: voulez-vous créer une archive avec une structure "plate" (c'est-à-dire tous les fichiers mélangés dans un répertoire)?
rozcietrzewiacz
1
Vous pouvez créer un nouveau répertoire find mydir -type f |xargs cp -t tempdir, puis tar tempdir.
Kevin
@rozcietrzewiacz Oui, plat, mais uniquement à partir de ce répertoire, pas à partir de sous-répertoires.
ateiob
1
OK, je pense que je vois ce que vous essayez de faire. Que diriez-vousfind mydir -depth 1 -type f | xargs tar cf mydir.tar
Kevin
2
Ah, les espaces. Utilisez FIND à la place exec: find mydir -maxdepth 1 -type f -exec tar cvf mydir.tar {} +. Le +met tous les fichiers sur la même ligne de commande comme xargs.
Kevin

Réponses:

11

Comme le fait remarquer camh, la commande précédente avait un petit problème en ce que, étant donné trop de noms de fichiers, elle s'exécuterait plus d'une fois, avec des invocations ultérieures effaçant silencieusement les exécutions précédentes. Comme nous ne compressons pas trop, nous pouvons ajouter au lieu d'écraser:

find mydir -maxdepth 1 -type f -print0 | xargs -0 tar Avf mydir.tar
find mydir -maxdepth 1 -type f -exec tar Avf mydir.tar {} +

La réponse d' Iocnarz concernant l' utilisation tardes options --nullet des -Toptions fonctionne également. Si vous avez cpioinstallé, la réponse de camh en l' utilisant est également très bien. Et si vous l'avez zshet ne vous dérange pas de l'utiliser pour une commande, la réponse de Gilles en utilisant un zsh glob ( *(.)) semble la plus simple.


La clé était l' -maxdepthoption. Réponse finale, gestion appropriée des espaces:

find mydir -maxdepth 1 -type f -print0 | xargs -0 tar cvf mydir.tar

Cela devrait également fonctionner:

find mydir -maxdepth 1 -type f -exec tar cvf mydir.tar {} +
Kevin
la source
4
Les deux peuvent entraîner plusieurs invocations de tar. Les deux xargset findavec la +variante ont un nombre maximum d'arguments qui peuvent être passés à tar. Cela entraînera la deuxième invocation de tar en écrasant la sortie de la première.
camh
2
En développant la limite xargs, xargs prend par défaut une ligne de commande maximale de 128 Ko. Si la liste des fichiers est plus grande, vous obtenez une seconde (ou plusieurs) invocation de la commande (tar), entraînant une perte de données silencieuse. Vous pouvez utiliser -xpour forcer les xargs à échouer au lieu de perdre des données, et bien que mieux qu'un bogue de perte de données silencieux, ce n'est toujours pas idéal. Ce bogue de tri est si dangereux car tout semble correct au premier abord, mais au fur et à mesure que la liste des fichiers s'allonge, vous commencez à le déclencher et ne le remarquerez peut-être pas avant d'essayer de restaurer votre sauvegarde. Alors c'est trop tard.
camh
@camh Vous avez raison, merci de l'avoir signalé; J'ai mis à jour pour refléter cela.
Kevin
1
La "réponse finale" n'est pas correcte, si vous utilisez "tar c" sans -T, vous pourriez obtenir des résultats partiels.
Eckes
14

Lorsque vous souhaitez utiliser findavec tar, la meilleure façon est d'utiliser à la cpioplace de tar. cpiopeut écrire des archives tar et est conçu pour prendre la liste des fichiers à archiver depuis stdin.

find mydir -maxdepth 1 -type f -print0 | cpio -o -H ustar -0 > mydir.tar

Utiliser findet cpioest une approche plus unix-y dans la mesure où vous laissez findfaire la sélection de fichiers avec toute la puissance dont il dispose, et laissez cpiofaire l'archivage. Il vaut la peine d'apprendre cette utilisation simple de cpio, car vous trouvez facile de résoudre les problèmes contre lesquels vous vous cognez en essayant tar.

camh
la source
Brillant! J'ai utilisé cpio dans un passé lointain, mais je n'ai jamais connu l'option ustar.
Ian McGowan
2
Cela a fonctionné beaucoup mieux pour moi que la réponse acceptée.
Dale Anderson
1
juste un peu. le -maxdepth 1 devrait précéder le -type f ou vous obtiendrez un avertissement de certaines trouvailles
kdubs
Merci @kdubs. J'ai mis à jour la réponse à mettre -maxdepthavant -type.
camh
3

Je ne suis pas sûr de comprendre vos exigences. Si vous souhaitez stocker les fichiers normaux dans mydirmais pas dans ses sous-répertoires, la manière la plus simple est d'utiliser zsh, où la correspondance des fichiers normaux uniquement est la simple question d'utiliser le . qualificatif glob :

tar cf mydir.tar mydir/*(.)
Gilles 'SO- arrête d'être méchant'
la source
3

Vous pouvez même utiliser find ... -print0et tar ... --nulldirectement sans utiliser xargsdu tout.

find . -maxdepth 1 -type f -print0 | tar cvf mydir.tar --null -T -

Dans l'exemple donné, l' --no-recursionoption to tarn'est pas nécessaire car seuls les chemins des fichiers (et non des répertoires) seront passés de findàtar .

Toutefois, l'utilisation de l' --no-recursionoption tardans l'exemple suivant empêche le tardouble archivage des répertoires. findfera la récursion de l'arborescence de répertoires au lieu de taralors.

# compare
find . -print0 | tar cf mydir.tar --null -T -
tar -tf mydir.tar | nl

find . -print0 | tar cf mydir.tar --null --no-recursion -T -
tar -tf mydir.tar | nl
locnarz
la source
2

Comme le dit le paragraphe d'introduction man tar(dernière phrase),

L'utilisation d'un nom de répertoire implique toujours que les sous-répertoires ci-dessous doivent être inclus dans l'archive.

Ce que je comprends comme une réponse «non» à votre question.

rozcietrzewiacz
la source
Bonne prise, sauf que le goudron comprend désormais de nombreux meachisms d'exclusion (par exemple --no-recursion, --exclude-tagetc.). Je regarde --exclude-tagce qui semble prometteur mais semble être l'exact opposé de ce que je recherche.
ateiob
J'ai essayé cela et j'ai vu des caractères supprimés des longs chemins d'accès. L'utilisation de tar avec -T et --null comme proposé par camh a évité ce problème.
Paul Brannan
1
star -c -C startdir -find . ! -type d > out.tar

Omettre -C startdiret remplacer .parstartdir s'il doit apparaître dans l'archive.

Il s'agit de la méthode la plus efficace basée sur les fonctionnalités de libfind. Libfind propose également des primaires -chown -chgrp -chmodqui modifient la stat struct en place et permettent d'archiver différentes métadonnées. Cela fonctionne également en mode liste et extraction et évite d'avoir à extraire l'archive entière dans de nombreux cas.

schily
la source
Pouvez-vous utiliser -finden -copymode. Le synopsis de la page de manuel suggère que vous pouvez, mais je n'ai pas pu le faire fonctionner (en essayant de répondre Comment copier des fichiers modifiés tout en préservant la structure des dossiers ) (avec schily-2016-02-10)
Stéphane Chazelas
Je n'ai pas testé cela plus longtemps. Il se peut qu'il y ait actuellement un bug. La page de manuel indique que le dernier argument serait le répertoire d'extraction, mais quand j'essaye ceci, j'obtiens: "Les arguments de chemin ne sont pas encore supportés en mode d'extraction". Est-ce ce que vous obtenez lorsque vous essayez?
schily
Oui. La page de manuel indique également que vous ne pouvez trouver des arguments qu'après -find mais si je mets le répertoire de destination avant -find, j'obtiens également une erreur
Stéphane Chazelas
Il existe du code pour désactiver le code de recherche dans le processus d'extraction et le message d'erreur provient d'une vérification incorrecte qui attend -c mais qui devrait également autoriser -copy. En mode -copy, l'analyseur find ne doit pas inclure le dernier argument.
schily
1
Une solution finale a maintenant été publiée dans les outils schily à sourceforge.net/projects/schilytools/files/schily-2016-03-11.tar.bz2 cela corrige également un problème à partir d'un setlocale () manquant dans star et cela permet - Répertoire C pour star -find.
schily
0

J'aurais peut-être trouvé une solution.

find mydir -type f -printf '%P\0'|tar czvf mydir.tar.gz -C mydir --null -T -

Cela peut être un peu coûteux, mais de toute façon cela fonctionnera, car cela ne dépend pas de xargs.

ciel
la source
-1

dir = your_dir; cd $ dir; tar -cvf file.tar `find. -maxdepth 1 -type f -print`

H Bosch
la source