Wie tariere ich ein Verzeichnis mit Dateien und Ordnern, ohne das Verzeichnis selbst einzuschließen?


382

Ich mache normalerweise:

tar -czvf my_directory.tar.gz my_directory

Was ist, wenn ich nur alles (einschließlich aller versteckten Systemdateien) in my_directory aufnehmen möchte, aber nicht das Verzeichnis selbst? Ich will nicht:

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

Ich möchte:

my_file
my_file
my_file

Ist das das Standardverhalten tar -czf? In meinem Fall werden nur die Dateien und nicht das Verzeichnis gespeichert. Wenn ich nur tardas Verzeichnis habe, enthält es es, aber mit tar -czfihm werden nur die Dateien hinzugefügt.
Durga Swaroop

Antworten:


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

sollte den Job in einer Zeile erledigen. Es funktioniert auch gut für versteckte Dateien. "*" erweitert versteckte Dateien zumindest in bash nicht um die Pfadnamenerweiterung. Unten ist mein Experiment:

$ 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

2
Dies funktioniert auch bei Dateien mit Leerzeichen oder anderen Sonderzeichen. Gut gemacht!
PanCrit

29
Nicht perfekt - TAR-Datei enthält '.' und auch ./file1 statt nur file1. Ich mag die Lösung von mateusza unten, um --strip-Komponenten beim Enteeren zu verwenden.
Ivan

23
@Ivan wenn Sie ersetzen .mit *so der Befehl sein wird , cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..dann wird es funktionieren wie erwartet.
Anonym

3
@jmathew Sie können auch eine Subshell verwenden, damit sich das Arbeitsverzeichnis Ihrer aktuellen Shell nicht ändert:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec

Ich weiß, dass es eine alte Antwort ist, aber cdin Verzeichnisse und aus zu gehen ist ziemlich lahm. Könnte zumindest Gebrauch pushdund popdwenn tarhatte keine Fahnen wie -C.
Andris

667

Verwenden Sie den -CSchalter von Teer:

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

Das -C my_directoryweist tar an, das aktuelle Verzeichnis zu ändern my_directory, und .bedeutet dann "das gesamte aktuelle Verzeichnis hinzufügen" (einschließlich versteckter Dateien und Unterverzeichnisse).

Stellen Sie sicher, dass Sie dies tun, -C my_directorybevor Sie dies tun. .Andernfalls erhalten Sie die Dateien im aktuellen Verzeichnis.


5
+1 danke! Es war das verdammte '.' Ich habe gefehlt. so erschwerend
JCotton

14
"Im Gegensatz zu den meisten Optionen wird -C an dem Punkt verarbeitet, an dem es in der Liste der zu verarbeitenden Dateien auftritt. Beachten Sie den folgenden Befehl: tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.a" apl.jhu.edu/Misc/Unix-info/tar/tar_65.html Ich versuche immer tar -czvf my_directory.tar.gz * -C my_directoryund das funktioniert nicht. -CLage ist wichtig! Verdammter Teer ...
m-ric

57
Nicht perfekt - TAR-Datei enthält '.' und auch ./file1 statt nur file1. Ich mag die Lösung von mateusza unten, um --strip-Komponenten beim Enteeren zu verwenden.
Ivan

3
@ Superole: Die Shell ersetzt die Platzhalter, bevor Teer ausgeführt wird. Beachten Sie auch, dass die Verwendung eines Platzhalters wie *keine versteckten Dateien enthält (was die ursprüngliche Anforderung war).
Dubek

28
Es erstellt . als Stammverzeichnis in .tar.gz.
Anonym

59

Sie können das Archiv auch wie gewohnt erstellen und extrahieren mit:

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

3
Diese Lösung ist besonders gut in Situationen, in denen Sie mit Tarballs arbeiten, die erstellt wurden, bevor alle Ihre Anforderungen bekannt waren ...
Digger

2
Beachten Sie, dass dies --strip-componentseine GNU-Erweiterung ist.
Zneak

2
Diese Antwort kann verbessert werden, indem das Beispiel "wie üblich" im Kontext angegeben wird.
Josh Habdas

33

Werfen Sie einen Blick auf --transform/ --xform, es gibt Ihnen die Möglichkeit, den Dateinamen zu massieren, wenn die Datei zum Archiv hinzugefügt wird:

% 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

Der Transformationsausdruck ähnelt dem von sed, und wir können andere Trennzeichen als /( ,im obigen Beispiel) verwenden.
https://www.gnu.org/software/tar/manual/html_section/tar_52.html


3
Ich würde das tun. Alles andere ist nur ein Hack!
JWG

2
Dies ist eine viel bessere Lösung.
Leesei

Dies ist die beste Lösung.
Nur die Hälfte

1
Gute Lösung, aber es könnte verursachen file list too long. Meine Lösung verhindert das und ist auch flexibler.
Über den

Dies ist eine großartige Lösung. Sie können auch --xformmehrere Pfade mehrmals übergeben.
2.

26

TL; DR

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

Unter bestimmten Bedingungen (nur Dateien, Verzeichnisse und Symlinks archivieren):

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

Erläuterung

Das Folgende enthält leider ein übergeordnetes Verzeichnis ./im Archiv:

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

Sie können alle Dateien mithilfe der --transformKonfigurationsoption aus diesem Verzeichnis verschieben , das .Verzeichnis selbst wird jedoch nicht entfernt . Es wird immer schwieriger, den Befehl zu zähmen.

Sie können $(find ...)dem Befehl eine Dateiliste hinzufügen (wie in Magnus 'Antwort ), dies führt jedoch möglicherweise zu einem Fehler "Dateiliste zu lang". Der beste Weg ist, es mit der -TOption von tar zu kombinieren , wie folgt :

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

Grundsätzlich werden alle Dateien ( -type f), Links ( -type l) und Unterverzeichnisse ( -type d) in Ihrem Verzeichnis -printf "%P\n"aufgelistet , alle Dateinamen relativ mit verwendet und diese dann an den Befehl tar übergeben (Dateinamen werden von STDIN mit verwendet -T -). Die -COption wird benötigt, damit tar weiß, wo sich die Dateien mit den relativen Namen befinden. Das --no-recursionFlag ist so, dass tar nicht in Ordner zurückkehrt, die archiviert werden sollen (was zu doppelten Dateien führt).

Wenn Sie mit Dateinamen etwas Besonderes tun müssen (Filtern, Folgen von Symlinks usw.), ist der findBefehl ziemlich leistungsfähig und Sie können ihn testen, indem Sie einfach den tarTeil des obigen Befehls entfernen :

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

Wenn Sie beispielsweise PDF-Dateien filtern möchten, fügen Sie hinzu ! -name '*.pdf'

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

Nicht-GNU-Fund

Der Befehl verwendet printf(in GNU verfügbar find) find, um die Ergebnisse mit relativen Pfaden zu drucken. Wenn Sie jedoch keine GNU haben find, werden die Pfade dadurch relativiert (entfernt Eltern mit 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 -

2
Gute Antwort. Sehr aufwändig und vor allem löst das Problem perfekt.
Alex

16

Diese Antwort sollte in den meisten Situationen funktionieren. Beachten Sie jedoch, wie die Dateinamen beispielsweise in der TAR-Datei gespeichert werden ./file1und nicht nur file1. Ich stellte fest, dass dies Probleme verursachte, wenn diese Methode zum Bearbeiten von Tarballs verwendet wurde, die als Paketdateien in BuildRoot verwendet wurden .

Eine Lösung besteht darin, einige Bash-Globs zu verwenden, um alle Dateien aufzulisten, mit Ausnahme der folgenden ..:

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

Dies ist ein Trick, den ich aus dieser Antwort gelernt habe .

Jetzt gibt tar einen Fehler zurück, wenn keine übereinstimmenden Dateien ..?*oder vorhanden .[^.]*sind, dies funktioniert jedoch weiterhin. Wenn der Fehler ein Problem ist (Sie überprüfen, ob ein Skript erfolgreich ist), funktioniert dies:

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

Obwohl wir jetzt mit Shell-Optionen herumspielen, könnten wir entscheiden, dass es ordentlicher ist, *versteckte Dateien abzugleichen :

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

Dies funktioniert möglicherweise nicht, wenn sich Ihre Shell *im aktuellen Verzeichnis befindet. Verwenden Sie daher alternativ:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob

1
Ich erhalte dabei seltsame Fehler. tar: start.sh: Cannot stat: No such file or directoryDies passiert mit allen Dateien in meinem aktuellen Verzeichnis! Wie vermeide ich das?
BrainStone

@BrainStone Ich bekomme genau die gleichen Ergebnisse.
mbmast

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

2
Hal fragte ausdrücklich nach versteckten Dateien. Du brauchst ausserdem .??*.
PanCrit

2
-1: Dadurch werden die versteckten Dateien nicht zum Teer hinzugefügt. Siehe die Antwort von tbman.
Dubek

3

Wenn es sich um ein Unix / Linux-System handelt und Sie sich für versteckte Dateien interessieren (die von * übersehen werden), müssen Sie Folgendes tun:

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

Ich weiß nicht, wie versteckte Dateien unter Windows aussehen.


2

Ich würde die folgende Bash-Funktion vorschlagen (erstes Argument ist der Pfad zum Verzeichnis, zweites Argument ist der Basisname des resultierenden Archivs):

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"
}

Sie können es folgendermaßen ausführen:

$ tar_dir_contents /path/to/some/dir my_archive

und es wird das Archiv my_archive.tar.gzim aktuellen Verzeichnis generiert . Es funktioniert mit versteckten (. *) Elementen und mit Elementen, deren Dateiname Leerzeichen enthält.


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

Dieser hat bei mir funktioniert und enthält alle versteckten Dateien, ohne alle Dateien in einem Stammverzeichnis mit dem Namen "." wie in Tomoes Antwort :


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

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

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

Beispiel:

tar.create folder

Bitte schön.


1

Das funktioniert bei mir.

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

Sie könnten auch verwenden

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

Im ersten Befehl gibt find eine Liste der Dateien und Unterverzeichnisse von my_dir zurück . Das Verzeichnis my_dir ist jedoch selbst als '.' In dieser Liste enthalten. Der Parameter -printf entfernt den vollständigen Pfad einschließlich des '.' und auch alle Die In der Formatzeichenfolge '% P' von printf verbleibt ein Rest in der Liste der Dateien und Unterverzeichnisse von my_dir und kann durch ein führendes Leerzeichen im Ergebnis des Befehls find angezeigt werden .

Dies ist für TAR kein Problem, aber wenn Sie dies beheben möchten, fügen Sie -mindepth 1 wie im zweiten Befehl hinzu.


0

Verwenden Sie pax.

Pax ist ein veraltetes Paket, macht aber die Arbeit perfekt und auf einfache Weise.

pax -w > mydir.tar mydir

Am praktischsten und macht den Job +1
Breno Salgado

Dieser Befehl erstellt mydir.tar mit folgenden Inhalten: mydir / file1 mydir / file2, genau das, was vermieden werden sollte.
Alex

0

Der einfachste Weg, den ich gefunden habe:

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


1
Das schließt versteckte Dateien nicht ein.
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=-
}

Behandelt Dateinamen sicher mit Leerzeichen oder anderen ungewöhnlichen Zeichen. Sie können -name '*.sql'dem Befehl find optional einen oder einen ähnlichen Filter hinzufügen , um die enthaltenen Dateien einzuschränken.


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

Wenn es sich bei dem Ordner um mytemp handelt, werden alle Dateien im Ordner komprimiert und entfernt, aber in Ruhe gelassen

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

Sie können Ausschlussmuster angeben und auch angeben, dass nicht in Unterordner geschaut werden soll


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.