Jak spakować katalog plików i folderów bez dołączania samego katalogu?

382

Zazwyczaj robię:

tar -czvf my_directory.tar.gz my_directory

Co jeśli chcę po prostu dołączyć wszystko (w tym ukryte pliki systemowe) do mojego katalogu, ale nie sam katalog? Nie chce:

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

Chcę:

my_file
my_file
my_file
l'L'l
źródło
Czy to jest domyślne zachowanie tar -czf? W moim przypadku jest to tylko przechowywanie plików, a nie katalogu. Kiedy tylko tarkatalog zawiera go, ale wraz z tar -czfnim dodaje tylko pliki.
Durga Swaroop

Odpowiedzi:

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

powinien wykonać pracę w jednej linii. Działa również dobrze w przypadku ukrytych plików. „*” nie rozwija ukrytych plików przez rozszerzenie nazwy ścieżki przynajmniej w bash. Poniżej znajduje się mój eksperyment:

$ 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
źródło
2
Będzie to również działać na plikach ze spacjami lub innymi znakami specjalnymi. Dobra robota!
PanCrit
29
Niezupełnie - plik tar zawiera „.” a także ./file1 zamiast po prostu file1. Podoba mi się rozwiązanie mateusza poniżej, aby podczas rozpakowywania używać --strip-components.
Ivan
23
@Ivan jeśli zastąpi .się *więc polecenie będzie cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..wtedy będzie działać zgodnie z oczekiwaniami.
Anonimowy
3
@jmathew Możesz także użyć podpowłoki, aby katalog roboczy bieżącej powłoki nie zmienił się:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec
Wiem, że to stara odpowiedź, ale cdwchodzenie do katalogów i obecnie jest dość kiepskie. Przynajmniej mógłbym użyć, pushda popdjeśli tarnie miałby takich flag -C.
Andris
667

Użyj -Cprzełącznika tar:

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

-C my_directoryMówi smołę, aby zmienić bieżący katalog my_directory, a następnie .oznacza „dodać cały katalog bieżący” (w tym ukrytych plików i podkatalogów).

Upewnij się, że to zrobisz, -C my_directoryzanim to zrobisz, w .przeciwnym razie otrzymasz pliki w bieżącym katalogu.

dubek
źródło
5
+1 dziękuję! To było cholerne ”. Brakowało mi. tak
irytujące
14
„W przeciwieństwie do większości opcji -C jest przetwarzany w momencie występuje w liście plików do przetworzenia Rozważmy następującą komendę:. tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.aApl.jhu.edu/Misc/Unix-info/tar/tar_65.html Zawsze staram tar -czvf my_directory.tar.gz * -C my_directoryi To nie działa. -Clokalizacja jest ważna! Cholerna tar ...
m-ric
57
Niezupełnie - plik tar zawiera „.” a także ./file1 zamiast po prostu file1. Podoba mi się rozwiązanie mateusza poniżej, aby podczas rozpakowywania używać --strip-components.
Ivan
3
@Superole: powłoka zastępuje symbole wieloznaczne przed uruchomieniem tar. Należy również pamiętać, że użycie znaku wieloznacznego *nie będzie obejmować ukrytych plików (co było pierwotnym wymogiem).
dubek
28
To tworzy . jako katalog główny w .tar.gz.
Anonimowy
59

Możesz także utworzyć archiwum jak zwykle i rozpakować je za pomocą:

tar --strip-components 1 -xvf my_directory.tar.gz
mateusza
źródło
3
To rozwiązanie jest szczególnie dobre w sytuacjach, gdy pracujesz z tarballami utworzonymi, zanim wszystkie Twoje wymagania były znane ...
Digger
2
Pamiętaj, że --strip-componentsjest to rozszerzenie GNU.
zneak
2
Odpowiedź można poprawić, podając przykładowy „jak zwykle” w kontekście.
Josh Habdas
33

Spójrz na --transform/ --xform, daje możliwość masowania nazwy pliku, gdy plik jest dodawany do archiwum:

% 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

Wyrażenie transformacji jest podobne do wyrażenia sedi możemy użyć separatorów innych niż /( ,w powyższym przykładzie).
https://www.gnu.org/software/tar/manual/html_section/tar_52.html

Magnus
źródło
3
Zrobiłbym to. Wszystko inne to tylko hack!
jwg,
2
To jest znacznie lepsze rozwiązanie.
leesei
To najlepsze rozwiązanie.
justhalf
1
Dobre rozwiązanie, ale może powodować file list too long. Moje rozwiązanie temu zapobiega i jest również bardziej elastyczne.
aross
To świetne rozwiązanie. Możesz także przejść --xformwiele razy dla wielu ścieżek.
elig
26

TL; DR

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

Z pewnymi warunkami (archiwizuj tylko pliki, katalogi i dowiązania symboliczne):

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

Wyjaśnienie

Poniżej niestety zawiera katalog nadrzędny ./w archiwum:

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

Możesz przenieść wszystkie pliki z tego katalogu, korzystając z --transformopcji konfiguracji, ale to nie pozbędzie .samego katalogu. Coraz trudniej oswoić polecenie.

Możesz użyć, $(find ...)aby dodać listę plików do polecenia (jak w odpowiedzi Magnusa ), ale to potencjalnie powoduje błąd „zbyt długa lista plików”. Najlepszym sposobem jest połączenie go z -Topcją tar :

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

Zasadniczo robi listę wszystkich plików ( -type f), links ( -type l) i podkatalogów ( -type d) w twoim katalogu, czyni wszystkie nazwy plików względnymi za pomocą -printf "%P\n", a następnie przekazuje je do komendy tar (pobiera nazwy plików z STDIN -T -). -CKonieczna jest opcja tak smoła wie, gdzie znajdują się pliki o nazwach względnych. --no-recursionFlaga jest tak, że smoła nie rekursja w folderach to powiedział do archiwum (powodując zduplikowane pliki).

Jeśli potrzebujesz zrobić coś specjalnego z nazwami plików (filtrowanie, śledzenie dowiązań symbolicznych itp.), findPolecenie jest dość wydajne i możesz je przetestować, usuwając tylko tarczęść powyższego polecenia:

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

Na przykład, jeśli chcesz filtrować pliki PDF, dodaj ! -name '*.pdf'

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

Nie znaleziono GNU

Polecenie używa printf(dostępne w GNU find), które każe findwypisywać wyniki ze ścieżkami względnymi. Jeśli jednak nie masz GNU find, działa to tak, aby ścieżki były względne (usuwa rodziców z 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
źródło
2
Świetna odpowiedź. Bardzo skomplikowane i, co najważniejsze, doskonale rozwiązuje problem.
Alex
16

Ta odpowiedź powinna działać w większości sytuacji. Zauważ jednak, jak nazwy plików są przechowywane w pliku tar jako na przykład, ./file1a nie tylko file1. Odkryłem, że spowodowało to problemy podczas korzystania z tej metody do manipulowania plikami tar używanymi jako pliki pakietów w BuildRoot .

Jednym z rozwiązań jest użycie niektórych globów Bash do wyświetlenia listy wszystkich plików z wyjątkiem ..tego:

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

To jest sztuczka, której nauczyłem się z tej odpowiedzi .

Teraz tar zwróci błąd, jeśli nie ma pasujących plików ..?*lub .[^.]*, ale nadal będzie działać. Jeśli błąd jest problemem (sprawdzasz sukces w skrypcie), działa to:

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

Chociaż teraz mamy do czynienia z opcjami powłoki, możemy zdecydować, że fajniej jest *dopasować ukryte pliki:

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

Może to nie działać, gdy globus powłoki znajduje się *w bieżącym katalogu, więc alternatywnie użyj:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
Rob Fisher
źródło
1
Gdy to robię, pojawiają się dziwne błędy. tar: start.sh: Cannot stat: No such file or directoryDzieje się tak ze wszystkimi plikami w moim bieżącym katalogu! Jak tego uniknąć?
BrainStone
@BrainStone Otrzymuję dokładnie takie same wyniki.
mbmast,
15
cd my_directory
tar zcvf ../my_directory.tar.gz *
mateusza
źródło
2
Hal wyraźnie zapytał o ukryte pliki. Potrzebujesz również .??*.
PanCrit
2
-1: To nie dodaje ukrytych plików do tar. Zobacz odpowiedź tbmana.
dubek
3

Jeśli jest to system Unix / Linux i zależy Ci na ukrytych plikach (które zostaną pominięte przez *), musisz:

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

Nie wiem, jak wyglądają ukryte pliki w systemie Windows.

PanCrit
źródło
2

Proponuję następującą funkcję Bash (pierwszy argument to ścieżka do katalogu, drugi argument to nazwa bazy wynikowego archiwum):

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

Możesz uruchomić go w następujący sposób:

$ tar_dir_contents /path/to/some/dir my_archive

i wygeneruje archiwum my_archive.tar.gzw bieżącym katalogu. Działa z ukrytymi (. *) Elementami i elementami ze spacjami w nazwie pliku.

gpz500
źródło
2
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

Ten działał dla mnie i obejmuje wszystkie ukryte pliki bez umieszczania wszystkich plików w katalogu głównym o nazwie „.” jak w odpowiedzi Tomoe :

med
źródło
1
tar.create() {
        local folder="${1}"

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

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

Przykład:

tar.create folder

Zapraszamy.

mmm
źródło
1

To działa dla mnie.

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

Możesz także użyć

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

W pierwszym poleceniu find zwraca listę plików i podkatalogów katalogu mój_katalog . Jednak katalog mój_katalog sam jest zawarty na tej liście jako „.” -printf parametr usuwa pełną ścieżkę tym, że „” a także wszystko Jednakże w format string „% P” z printf liście resztka w liście plików i podkatalogów z my_dir i mogą być postrzegane przez czołowego miejsca w wyniku znajdowania polecenia.

Nie będzie to problemem dla TAR, ale jeśli chcesz to naprawić, dodaj -mindepth 1 jak w drugim poleceniu.

Serendrewpity
źródło
0

Użyj pax.

Pax to przestarzałe opakowanie, ale wykonuje to zadanie idealnie i w prosty sposób.

pax -w > mydir.tar mydir
rjv
źródło
Najbardziej praktyczny i wykonuje pracę +1
Breno Salgado
to polecenie tworzy mydir.tar z zawartością: mydir / file1 mydir / file2, dokładnie tego, czego należało unikać.
Alex
0

Najprostszy sposób, w jaki znalazłem:

cd mój_katalog && tar -czvf ../my_dir.tar.gz *

alexgo
źródło
1
To nie będzie zawierać ukrytych plików.
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=-
}

Bezpiecznie obsługuje nazwy plików ze spacjami lub innymi nietypowymi znakami. Możesz opcjonalnie dodać -name '*.sql'podobny lub podobny filtr do polecenia find, aby ograniczyć dołączone pliki.

marcingo
źródło
-1
 tar -cvzf  tarlearn.tar.gz --remove-files mytemp/*

Jeśli folder jest mytemp, to jeśli zastosujesz powyższe, zostanie on skompresowany i usunie wszystkie pliki w folderze, ale zostaw go w spokoju

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

Możesz podać wzorce wykluczania, a także określić, aby nie przeglądać również podfolderów

użytkownik1456599
źródło
-3
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`
mateusza
źródło