Comment tarer un répertoire de fichiers et de dossiers sans inclure le répertoire lui-même?

382

Je fais généralement:

tar -czvf my_directory.tar.gz my_directory

Que faire si je veux simplement tout inclure (y compris les fichiers système cachés) dans mon_répertoire, mais pas le répertoire lui-même? Je ne veux pas:

my_directory
   --- my_file
   --- my_file
   --- my_file

Je voudrais:

my_file
my_file
my_file
je vais
la source
Est-ce le comportement par défaut de faire tar -czf? Dans mon cas, il s'agit uniquement de stocker les fichiers et non le répertoire. Quand je viens tardu répertoire, il l'inclut, mais avec lui, tar -czfil ajoute seulement les fichiers.
Durga Swaroop

Réponses:

233
cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd - 

devrait faire le travail sur une seule ligne. Cela fonctionne aussi bien pour les fichiers cachés. "*" ne développe pas les fichiers cachés par extension du nom de chemin au moins dans bash. Voici mon expérience:

$ mkdir my_directory
$ touch my_directory/file1
$ touch my_directory/file2
$ touch my_directory/.hiddenfile1
$ touch my_directory/.hiddenfile2
$ cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd ..
./
./file1
./file2
./.hiddenfile1
./.hiddenfile2
$ tar ztf my_dir.tgz
./
./file1
./file2
./.hiddenfile1
./.hiddenfile2
tomoe
la source
2
Cela fonctionnera également sur les fichiers avec des espaces ou d'autres caractères spéciaux. Bon travail!
PanCrit
29
Pas parfait - le fichier tar contient '.' et aussi ./file1 au lieu de simplement file1. J'aime la solution de mateusza ci-dessous pour utiliser --strip-components lors du retrait.
Ivan
23
@Ivan si vous remplacez .par *ainsi la commande sera cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..alors elle fonctionnera comme vous vous y attendiez.
Anonyme
3
@jmathew Vous pouvez également utiliser un sous-shell pour que le répertoire de travail de votre shell actuel ne change pas:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec
Je sais que c'est une vieille réponse mais cdentrer dans les répertoires et sortir est assez boiteux. Pourrait au moins utiliser pushdet popds'il tarn'avait pas de drapeaux comme -C.
Andris
668

Utilisez le -Ccommutateur de tar:

tar -czvf my_directory.tar.gz -C my_directory .

Le -C my_directorydit à tar de changer le répertoire courant en my_directory, puis .signifie "ajouter tout le répertoire courant" (y compris les fichiers et sous-répertoires cachés).

Assurez-vous de le faire -C my_directoryavant de le faire, .sinon vous obtiendrez les fichiers dans le répertoire actuel.

dubek
la source
5
+1 merci! C'était le putain de '.' Je manquais. tellement aggravant
JCotton
14
"Contrairement à la plupart des options, -C est traité au point où il se produit dans la liste des fichiers à traiter. Considérez la commande suivante: tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.a" apl.jhu.edu/Misc/Unix-info/tar/tar_65.html J'essaie toujours tar -czvf my_directory.tar.gz * -C my_directoryet cela ne fonctionne pas. -Cl'emplacement est important! Merde tar ...
m-ric
57
Pas parfait - le fichier tar contient '.' et aussi ./file1 au lieu de simplement file1. J'aime la solution de mateusza ci-dessous pour utiliser --strip-components lors du retrait.
Ivan
3
@Superole: la coquille remplace les caractères génériques avant d'exécuter tar. Notez également que l'utilisation d'un caractère générique comme *n'inclura pas les fichiers cachés (ce qui était l'exigence d'origine).
dubek
28
Ça crée . comme répertoire racine dans .tar.gz.
Anonyme
59

Vous pouvez également créer des archives comme d'habitude et les extraire avec:

tar --strip-components 1 -xvf my_directory.tar.gz
mateusza
la source
3
Cette solution est particulièrement bonne dans les situations où vous travaillez avec des tarballs créés avant que toutes vos exigences ne soient connues ...
Digger
2
Attention, c'est --strip-componentsune extension GNU.
zneak
2
Cette réponse peut être améliorée en fournissant l'exemple "comme d'habitude" dans le contexte.
Josh Habdas
33

Jetez un œil à --transform/ --xform, cela vous donne la possibilité de masser le nom du fichier lorsque le fichier est ajouté à l'archive:

% mkdir my_directory
% touch my_directory/file1
% touch my_directory/file2
% touch my_directory/.hiddenfile1
% touch my_directory/.hiddenfile2
% tar -v -c -f my_dir.tgz --xform='s,my_directory/,,' $(find my_directory -type f)
my_directory/file2
my_directory/.hiddenfile1
my_directory/.hiddenfile2
my_directory/file1
% tar -t -f my_dir.tgz 
file2
.hiddenfile1
.hiddenfile2
file1

L'expression de transformation est similaire à celle de sed, et nous pouvons utiliser des séparateurs autres que /( ,dans l'exemple ci-dessus).
https://www.gnu.org/software/tar/manual/html_section/tar_52.html

Magnus
la source
3
Je ferais ça. Tout le reste n'est qu'un hack!
jwg
2
C'est une bien meilleure solution.
leesei
C'est la meilleure solution.
moitié du
1
Bonne solution, mais cela pourrait provoquer file list too long. Ma solution empêche cela et est également plus flexible.
2017
C'est une excellente solution. Vous pouvez également passer --xformplusieurs fois pour plusieurs chemins.
elig
26

TL; DR

find /my/dir/ -printf "%P\n" | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

Sous certaines conditions (archiver uniquement les fichiers, les répertoires et les liens symboliques):

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

Explication

Ce qui suit inclut malheureusement un répertoire parent ./dans l'archive:

tar -czf mydir.tgz -C /my/dir .

Vous pouvez déplacer tous les fichiers hors de ce répertoire en utilisant l' --transformoption de configuration, mais cela ne supprime pas le .répertoire lui-même. Il devient de plus en plus difficile d'apprivoiser la commande.

Vous pouvez utiliser $(find ...)pour ajouter une liste de fichiers à la commande (comme dans la réponse de magnus ), mais cela peut potentiellement provoquer une erreur "liste de fichiers trop longue". La meilleure façon est de le combiner avec l' -Toption de tar , comme ceci:

find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -

Fondamentalement, il répertorie tous les fichiers ( -type f), liens ( -type l) et sous-répertoires ( -type d) de votre répertoire, rend tous les noms de fichiers relatifs à l'aide -printf "%P\n", puis transmet cela à la commande tar (il prend les noms de fichiers de STDIN à l'aide -T -). L' -Coption est nécessaire pour que tar sache où se trouvent les fichiers avec des noms relatifs. Le --no-recursiondrapeau est pour que tar ne rentre pas dans les dossiers qu'il est invité à archiver (provoquant des fichiers en double).

Si vous avez besoin de faire quelque chose de spécial avec les noms de fichiers (filtrage, suivi des liens symboliques, etc.), la findcommande est assez puissante, et vous pouvez la tester en supprimant simplement la tarpartie de la commande ci-dessus:

$ find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d
> textfile.txt
> documentation.pdf
> subfolder2
> subfolder
> subfolder/.gitignore

Par exemple, si vous souhaitez filtrer des fichiers PDF, ajoutez ! -name '*.pdf'

$ find /my/dir/ -printf "%P\n" -type f ! -name '*.pdf' -o -type l -o -type d
> textfile.txt
> subfolder2
> subfolder
> subfolder/.gitignore

Recherche non GNU

La commande utilise printf(disponible dans GNU find) qui indique findd'imprimer ses résultats avec des chemins relatifs. Cependant, si vous n'avez pas GNU find, cela fonctionne pour rendre les chemins relatifs (supprime les parents avec sed):

find /my/dir/ -type f -o -type l -o -type d | sed s,^/my/dir/,, | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
aross
la source
2
Très bonne réponse. Très élaboré, et surtout, résout parfaitement le problème.
Alex
16

Cette réponse devrait fonctionner dans la plupart des situations. Notez cependant comment les noms de fichiers sont stockés dans le fichier tar comme, par exemple, ./file1plutôt que simplement file1. J'ai constaté que cela causait des problèmes lors de l'utilisation de cette méthode pour manipuler les archives tar utilisées comme fichiers de package dans BuildRoot .

Une solution consiste à utiliser des globes Bash pour répertorier tous les fichiers, sauf ..comme ceci:

tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *

C'est une astuce que j'ai apprise de cette réponse .

Maintenant, tar renverra une erreur s'il n'y a aucun fichier correspondant à ..?*ou .[^.]*, mais cela fonctionnera toujours. Si l'erreur est un problème (vous vérifiez le succès dans un script), cela fonctionne:

shopt -s nullglob
tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
shopt -u nullglob

Bien que nous jouions maintenant avec les options du shell, nous pourrions décider qu'il est plus simple de faire *correspondre les fichiers cachés:

shopt -s dotglob
tar -C my_dir -zcvf my_dir.tar.gz *
shopt -u dotglob

Cela pourrait ne pas fonctionner là où vos globes shell *dans le répertoire en cours, alors alternativement, utilisez:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
Rob Fisher
la source
1
Je reçois des erreurs bizarres lorsque je fais cela tar: start.sh: Cannot stat: No such file or directoryCela arrive à tous les fichiers de mon répertoire actuel! Comment éviter cela?
BrainStone
@BrainStone J'obtiens exactement les mêmes résultats.
mbmast
15
cd my_directory
tar zcvf ../my_directory.tar.gz *
mateusza
la source
2
Hal a explicitement demandé des informations sur les fichiers cachés. Tu as aussi besoin .??*.
PanCrit
2
-1: Cela n'ajoute pas les fichiers cachés au tar. Voir la réponse de tbman.
dubek
3

Si c'est un système Unix / Linux, et que vous vous souciez des fichiers cachés (qui seront manqués par *), vous devez faire:

cd my_directory
tar zcvf ../my_directory.tar.gz * .??*

Je ne sais pas à quoi ressemblent les fichiers cachés sous Windows.

PanCrit
la source
2

Je proposerais la fonction Bash suivante (le premier argument est le chemin d'accès au répertoire, le deuxième argument est le nom de base de l'archive résultante):

function tar_dir_contents ()
{
    local DIRPATH="$1"
    local TARARCH="$2.tar.gz"
    local ORGIFS="$IFS"
    IFS=$'\n'
    tar -C "$DIRPATH" -czf "$TARARCH" $( ls -a "$DIRPATH" | grep -v '\(^\.$\)\|\(^\.\.$\)' )
    IFS="$ORGIFS"
}

Vous pouvez l'exécuter de cette façon:

$ tar_dir_contents /path/to/some/dir my_archive

et il générera l'archive my_archive.tar.gzdans le répertoire courant. Il fonctionne avec des éléments cachés (. *) Et avec des éléments avec des espaces dans leur nom de fichier.

gpz500
la source
2
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

Celui-ci a fonctionné pour moi et il inclut tous les fichiers cachés sans mettre tous les fichiers dans un répertoire racine nommé "." comme dans la réponse de tomoe :

med
la source
1
tar.create() {
        local folder="${1}"

        local tar="$(basename "${folder}")".tar.gz

        cd "${folder}" && tar -zcvf "../${tar}" .; cd - &> /dev/null
}

Exemple:

tar.create folder

Je vous en prie.

mmm
la source
1

C'est ce qui fonctionne pour moi.

tar -cvf my_dir.tar.gz -C /my_dir/ $(find /my_dir/ -maxdepth 1 -printf '%P ')

Vous pouvez également utiliser

tar -cvf my_dir.tar.gz -C /my_dir/ $(find /my_dir/ -mindepth 1 -maxdepth 1 -printf '%P ')

Dans la première commande, find renvoie une liste de fichiers et sous-répertoires de my_dir . Cependant, le répertoire my_dir est lui-même inclus dans cette liste en tant que '.' Le -printf paramètre supprime le chemin complet, y compris celui «.» et aussi tous Cependant, le dans la chaîne de format '% P' de printf laisse un reste dans la liste des fichiers et sous-répertoires de my_dir et peut être vu par un espace de tête dans le résultat de la commande find .

Ce ne sera pas un problème pour TAR mais si vous voulez résoudre ce problème, ajoutez -mindepth 1 comme dans la deuxième commande.

serendrewpity
la source
0

Utilisez pax.

Pax est un package obsolète, mais fait le travail parfaitement et de manière simple.

pax -w > mydir.tar mydir
rjv
la source
Le plus pratique et fait le travail +1
Breno Salgado
cette commande crée mydir.tar avec le contenu: mydir / file1 mydir / file2, exactement ce qui devait être évité.
Alex
0

Le moyen le plus simple que j'ai trouvé:

cd my_dir && tar -czvf ../my_dir.tar.gz *

alexgo
la source
1
Cela n'inclura pas les fichiers cachés.
asynts
0
# tar all files within and deeper in a given directory
# with no prefixes ( neither <directory>/ nor ./ )
# parameters: <source directory> <target archive file>
function tar_all_in_dir {
    { cd "$1" && find -type f -print0; } \
    | cut --zero-terminated --characters=3- \
    | tar --create --file="$2" --directory="$1" --null --files-from=-
}

Gère en toute sécurité les noms de fichiers avec des espaces ou d'autres caractères inhabituels. Vous pouvez éventuellement ajouter un -name '*.sql'filtre ou similaire à la commande find pour limiter les fichiers inclus.

marcingo
la source
-1
 tar -cvzf  tarlearn.tar.gz --remove-files mytemp/*

Si le dossier est mytemp, si vous appliquez ce qui précède, il compressera et supprimera tous les fichiers du dossier, mais laissez-le tranquille

 tar -cvzf  tarlearn.tar.gz --remove-files --exclude='*12_2008*' --no-recursion mytemp/*

Vous pouvez donner des motifs d'exclusion et également spécifier de ne pas regarder trop dans les sous-dossiers

user1456599
la source
-3
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`
mateusza
la source