web-dev-qa-db-fra.com

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

Je fais typiquement:

tar -czvf my_directory.tar.gz my_directory

Que se passe-t-il si je veux simplement tout inclure (y compris tous les fichiers système cachés) dans my_directory, 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
350
user4903
cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd - 

devrait faire le travail en une seule ligne. Cela fonctionne aussi bien pour les fichiers cachés. "*" ne développe pas les fichiers cachés par extension de nom de chemin au moins en bash. Ci-dessous 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
213
tomoe

Utilisez le commutateur -C de tar:

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

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

Assurez-vous de bien faire -C my_directory avant de faire . sinon vous aurez les fichiers dans le répertoire actuel.

604
dubek

Vous pouvez également créer une archive comme d'habitude et l'extraire avec:

tar --strip-components 1 -xvf my_directory.tar.gz
53
mateusza

Jetez un oeil à --transform/--xform, cela vous donne l'occasion de modifier le nom du fichier lorsque celui-ci 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

31
Magnus

TL; DR

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

Avec certaines conditions (archiver uniquement les fichiers, répertoires et 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

La liste ci-dessous 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'option de configuration --transform, 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 réponse de magnus ), mais cela peut entraîner une erreur "liste de fichiers trop longue". Le meilleur moyen est de le combiner avec l'option -T 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 -

En gros, il répertorie tous les fichiers (-type f), les liens (-type l) et les sous-répertoires (-type d) de votre répertoire, rend tous les noms de fichiers relatifs à l'aide de -printf "%P\n", puis passe cela à la commande tar (il prend les noms de fichiers de STDIN en utilisant -T -). L'option -C est nécessaire pour que tar sache où sont situés les fichiers portant des noms relatifs. Le drapeau --no-recursion évite que tar ne rentre dans les dossiers qu’il est ordonné d’archiver (ce qui entraîne la duplication de fichiers).

Si vous avez besoin de faire quelque chose de spécial avec les noms de fichiers (filtrage, liens symboliques, etc.), la commande find est assez puissante et vous pouvez le tester en supprimant simplement la partie tar 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 les 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 à find d’imprimer ses résultats avec des chemins relatifs. Cependant, si vous n'avez pas GNU find, cela rend 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 -
22
aross

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

Une solution consiste à utiliser certains globs Bash pour répertorier tous les fichiers à l'exception de .. comme ceci:

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

C’est un tour que j’ai appris de cette réponse .

Maintenant, tar renverra une erreur s'il n'y a pas de fichiers correspondant à ..?* ou .[^.]*, mais cela fonctionnera toujours. Si l'erreur pose 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 modifions maintenant les options de Shell, nous pourrions décider qu'il est préférable de faire correspondre * aux 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ù votre shell globs * dans le répertoire en cours, alors utilisez alternativement:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
16
Rob Fisher
cd my_directory
tar zcvf ../my_directory.tar.gz *
14
mateusza

S'il s'agit d'un système Unix/Linux et que vous vous souciez des fichiers cachés (ce qui manquera par *), vous devez procéder comme suit:

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

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

3
PanCrit
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

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

2
med

Je proposerais la fonction Bash suivante (le premier argument est le chemin du répertoire, le second 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 manière:

$ tar_dir_contents /path/to/some/dir my_archive

et il va générer l'archive my_archive.tar.gz dans le répertoire courant. Cela fonctionne avec les éléments cachés (. *) Et avec les éléments avec des espaces dans leur nom de fichier.

2
gpz500

Utilisez pax.

Pax est un paquet obsolète, mais fait le travail parfaitement et simplement.

pax -w > mydir.tar mydir
0
rjv

Plus simple j'ai trouvé:

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

0
alexgo
# 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 filtre -name '*.sql' ou un filtre similaire à la commande find pour limiter les fichiers inclus.

0
marcingo