Come posso tarare una directory di file e cartelle senza includere la directory stessa?


382

In genere faccio:

tar -czvf my_directory.tar.gz my_directory

Cosa succede se voglio solo includere tutto (compresi eventuali file di sistema nascosti) in my_directory, ma non la directory stessa? Non voglio

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

Voglio:

my_file
my_file
my_file

È questo il comportamento predefinito di fare tar -czf? Nel mio caso memorizza solo i file e non la directory. Quando ho solo tarla directory lo include ma con tar -czfesso sta solo aggiungendo i file.
Durga Swaroop,

Risposte:


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

dovrebbe fare il lavoro in una riga. Funziona bene anche per i file nascosti. "*" non espande i file nascosti per espansione del nome percorso almeno in bash. Di seguito è il mio esperimento:

$ 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
Questo funzionerà anche su file con spazi o altri caratteri speciali. Buon lavoro!
PanCrit,

29
Non perfetto: il file tar contiene '.' e anche ./file1 anziché solo file1. Mi piace la soluzione di mateusza qui sotto per usare --strip-componenti quando non si tira.
Ivan

23
@Ivan se si sostituisce .con *così il comando sarà cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..quindi funzionerà come previsto.
Anonimo

3
@jmathew Puoi anche usare una subshell in modo che la directory di lavoro della shell corrente non cambi:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec

So che è una vecchia risposta, ma cdentrare nelle directory e fuori è piuttosto zoppo. Potrebbe almeno usare pushde popdse tarnon avesse avuto flag come -C.
Andris,

668

Usa l' -Cinterruttore di tar:

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

La -C my_directorydice a tar di cambiare la directory corrente my_directory, e quindi .significa "aggiungere tutta la directory corrente" (inclusi i file nascosti e sotto-directory).

Assicurati di farlo -C my_directoryprima di farlo .altrimenti otterrai i file nella directory corrente.


5
+1 grazie! Era il dannato "." Mi mancava così aggravante
JCotton

14
"A differenza della maggior parte delle opzioni, -C viene elaborato nel punto in cui si trova nell'elenco dei file da elaborare. Considera il seguente comando: tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.a" apl.jhu.edu/Misc/Unix-info/tar/tar_65.html Provo sempre tar -czvf my_directory.tar.gz * -C my_directorye che non funziona. -Cla posizione è importante! Dannazione tar ...
m-ric

57
Non perfetto: il file tar contiene '.' e anche ./file1 anziché solo file1. Mi piace la soluzione di mateusza qui sotto per usare --strip-componenti quando non si tira.
Ivan

3
@Superole: la shell sostituisce i caratteri jolly prima di eseguire tar. Si noti inoltre che l'utilizzo di un carattere jolly come *non includerà i file nascosti (che era il requisito originale).
Dubek,

28
Crea . come directory principale in .tar.gz.
Anonimo

59

Puoi anche creare un archivio come al solito ed estrarlo con:

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

3
Questa soluzione è particolarmente utile nelle situazioni in cui stai lavorando con tarball creati prima che fossero noti tutti i tuoi requisiti ...
Digger,

2
Ricorda che --strip-componentsè un'estensione GNU.
zneak,

2
Questa risposta può essere migliorata fornendo l'esempio "come al solito" nel contesto.
Josh Habdas,

33

Dai un'occhiata a --transform/ --xform, ti dà la possibilità di massaggiare il nome del file quando il file viene aggiunto all'archivio:

% 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'espressione di trasformazione è simile a quella di sede possiamo usare separatori diversi da /( ,nell'esempio sopra).
https://www.gnu.org/software/tar/manual/html_section/tar_52.html


3
Vorrei fare questo. Nient'altro è solo un trucco!
jwg

2
Questa è una soluzione molto migliore.
leesei,

Questa è la soluzione migliore
solo il

1
Buona soluzione, ma potrebbe causare file list too long. La mia soluzione lo impedisce ed è anche più flessibile.
circa l'

Questa è un'ottima soluzione Puoi anche passare --xformpiù volte per più percorsi.
idoneità

26

TL; DR

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

Con alcune condizioni (archivia solo file, directory e collegamenti simbolici):

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

Spiegazione

Di seguito purtroppo include una directory principale ./nell'archivio:

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

È possibile spostare tutti i file da quella directory utilizzando l' --transformopzione di configurazione, ma ciò non elimina la .directory stessa. Diventa sempre più difficile domare il comando.

È possibile utilizzare $(find ...)per aggiungere un elenco di file al comando (come nella risposta di magnus ), ma ciò potrebbe potenzialmente causare un errore "Elenco file troppo lungo". Il modo migliore è combinarlo con l' -Topzione tar , in questo modo:

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

Fondamentalmente ciò che fa è elencare tutti i file ( -type f), i collegamenti ( -type l) e le sottodirectory ( -type d) nella directory, rendere tutti i nomi dei file relativi usando -printf "%P\n"e quindi passarli al comando tar (prende i nomi dei file da STDIN usando -T -). L' -Copzione è necessaria in modo che tar sappia dove si trovano i file con nomi relativi. Il --no-recursionflag è in modo tale che tar non ricorra nelle cartelle che gli viene detto di archiviare (causando file duplicati).

Se hai bisogno di fare qualcosa di speciale con i nomi dei file (filtro, seguendo i collegamenti simbolici ecc.), Il findcomando è piuttosto potente e puoi testarlo semplicemente rimuovendo la tarparte del comando sopra:

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

Ad esempio, se si desidera filtrare i file PDF, aggiungere ! -name '*.pdf'

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

Trova non GNU

Il comando usa printf(disponibile in GNU find) che dice finddi stampare i suoi risultati con percorsi relativi. Tuttavia, se non hai GNU find, questo funziona per rendere i percorsi relativi (rimuove i genitori con 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
Bella risposta. Molto elaborato e, soprattutto, risolve perfettamente il problema.
Alex

16

Questa risposta dovrebbe funzionare nella maggior parte delle situazioni. Si noti tuttavia come i nomi dei file sono memorizzati nel file tar come, ad esempio, ./file1anziché solo file1. Ho scoperto che questo ha causato problemi durante l'utilizzo di questo metodo per manipolare tarball usati come file di pacchetto in BuildRoot .

Una soluzione è utilizzare alcuni glob di Bash per elencare tutti i file ad eccezione di ..questo:

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

Questo è un trucco che ho imparato da questa risposta .

Ora tar restituirà un errore se non ci sono file corrispondenti ..?*o .[^.]*, ma funzionerà comunque. Se l'errore è un problema (stai verificando il successo in uno script), funziona:

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

Anche se ora stiamo scherzando con le opzioni della shell, potremmo decidere che è più ordinato avere *file nascosti corrispondenti:

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

Questo potrebbe non funzionare laddove la tua shell si trova *nella directory corrente, quindi in alternativa usa:

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

1
Ottengo errori strani quando lo faccio tar: start.sh: Cannot stat: No such file or directoryQuesto succede a tutti i file nella mia directory corrente! Come posso evitarlo?
BrainStone,

@BrainStone Ottengo esattamente gli stessi risultati.
mbmast,

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

2
Hal chiese esplicitamente dei file nascosti. Hai anche bisogno. ?? *.
PanCrit,

2
-1: questo non aggiunge i file nascosti al tar. Vedi la risposta di tbman.
Dubek,

3

Se si tratta di un sistema Unix / Linux e ti interessano i file nascosti (che verranno persi da *), devi fare:

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

Non so come siano i file nascosti sotto Windows.


2

Vorrei proporre la seguente funzione di Bash (il primo argomento è il percorso della directory, il secondo argomento è il nome di base dell'archivio risultante):

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

Puoi eseguirlo in questo modo:

$ tar_dir_contents /path/to/some/dir my_archive

e genererà l'archivio my_archive.tar.gznella directory corrente. Funziona con elementi nascosti (. *) E con elementi con spazi nel loro nome file.


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

Questo ha funzionato per me ed include tutti i file nascosti senza mettere tutti i file in una directory root denominata "." come nella risposta di tomoe :


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

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

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

Esempio:

tar.create folder

Prego.


1

Questo è ciò che funziona per me.

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

Puoi anche usare

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

Nel primo comando, find restituisce un elenco di file e sottodirectory di my_dir . Tuttavia, la directory my_dir è essa stessa inclusa in tale elenco come '.' Il parametro -printf rimuove l'intero percorso incluso quello '.' e anche tutto Comunque, il nella stringa di formato '% P' di printf lascia un residuo nell'elenco di file e sottodirectory di my_dir e può essere visto da uno spazio iniziale nel risultato del comando find .

Questo non sarà un problema per TAR ma se vuoi risolvere questo problema, aggiungi -mindepth 1 come nel secondo comando.


0

Usa pax.

Pax è un pacchetto deprecato ma fa il lavoro perfettamente e in modo semplice.

pax -w > mydir.tar mydir

Più pratico e fa il lavoro +1
Breno Salgado

questo comando crea mydir.tar con i contenuti: mydir / file1 mydir / file2, esattamente ciò che doveva essere evitato.
Alex,

0

Il modo più semplice che ho trovato:

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


1
Ciò non include i file nascosti.
asynts il

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

Gestisce in modo sicuro i nomi di file con spazi o altri caratteri insoliti. È possibile aggiungere facoltativamente un -name '*.sql'filtro simile o simile al comando find per limitare i file inclusi.


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

Se la cartella è mytemp, se si applica quanto sopra si comprimerà e rimuoverà tutti i file nella cartella, ma lasciandolo da solo

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

Puoi dare schemi di esclusione e anche specificare di non guardare anche nelle sottocartelle


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.