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
l'L'l
quelle
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
Tomoe
quelle
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.

Dubek
quelle
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
mateusza
quelle
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

Magnus
quelle
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 -
aross
quelle
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
Rob Fisher
quelle
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 *
mateusza
quelle
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.

PanCrit
quelle
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.

gpz500
quelle
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 :

med
quelle
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.

mmm
quelle
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.

Serendrewpity
quelle
0

Verwenden Sie pax.

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

pax -w > mydir.tar mydir
rjv
quelle
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 *

alexgo
quelle
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.

marcingo
quelle
-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

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