Bagaimana cara tar direktori file dan folder tanpa termasuk direktori itu sendiri?

382

Saya biasanya melakukan:

tar -czvf my_directory.tar.gz my_directory

Bagaimana jika saya hanya ingin memasukkan semuanya (termasuk file sistem tersembunyi) di my_directory, tetapi bukan direktori itu sendiri? Saya tidak mau:

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

Saya ingin:

my_file
my_file
my_file
aku akan
sumber
Apakah itu perilaku standar dari melakukan tar -czf? Dalam kasus saya ini hanya menyimpan file dan bukan direktori. Ketika saya hanya tardirektori itu termasuk tetapi dengan tar -czfitu hanya menambahkan file.
Durga Swaroop

Jawaban:

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

harus melakukan pekerjaan dalam satu baris. Ini berfungsi dengan baik untuk file tersembunyi juga. "*" tidak memperluas file tersembunyi dengan ekspansi nama jalur, setidaknya dalam bash. Di bawah ini adalah eksperimen saya:

$ 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
sumber
2
Ini juga akan berfungsi pada file dengan spasi atau karakter khusus lainnya. Kerja bagus!
PanCrit
29
Tidak sempurna - file tar berisi '.' dan juga ./file1 bukan hanya file1. Saya suka solusi oleh mateusza di bawah ini untuk menggunakan --strip-components ketika un-tarring.
Ivan
23
@Van jika Anda mengganti .dengan *sehingga perintah akan cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..maka itu akan berfungsi seperti yang Anda harapkan.
Anonim
3
@ jmathew Anda juga dapat menggunakan subkulit sehingga direktori kerja shell Anda saat ini tidak berubah:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec
Saya tahu ini jawaban lama tapi cdmasuk ke direktori dan keluar cukup timpang. Paling tidak bisa menggunakan pushddan popdjika tartidak memiliki bendera seperti -C.
Andris
668

Gunakan -Csakelar tar:

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

The -C my_directorymemberitahukan tar untuk mengubah direktori ke my_directory, dan kemudian .berarti "menambahkan seluruh direktori saat ini" (termasuk file tersembunyi dan sub-direktori).

Pastikan Anda melakukannya -C my_directorysebelum melakukannya .atau Anda akan mendapatkan file di direktori saat ini.

dubek
sumber
5
+1 terima kasih! Sialan. ' Aku menghilang. sangat menjengkelkan
JCotton
14
"Tidak seperti kebanyakan opsi, -C diproses pada saat itu terjadi dalam daftar file yang akan diproses. Pertimbangkan perintah berikut: tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.a" apl.jhu.edu/Misc/Unix-info/tar/tar_65.html Saya selalu mencoba tar -czvf my_directory.tar.gz * -C my_directorydan itu tidak bekerja. -Clokasi itu penting! Sialan ...
m-ric
57
Tidak sempurna - file tar berisi '.' dan juga ./file1 bukan hanya file1. Saya suka solusi oleh mateusza di bawah ini untuk menggunakan --strip-components ketika un-tarring.
Ivan
3
@Superole: shell mengganti wildcard sebelum menjalankan tar. Perhatikan juga bahwa menggunakan wildcard like *tidak akan menyertakan file tersembunyi (yang merupakan persyaratan asli).
dubek
28
Itu menciptakan. sebagai direktori root di .tar.gz.
Anonim
59

Anda juga dapat membuat arsip seperti biasa dan mengekstraknya dengan:

tar --strip-components 1 -xvf my_directory.tar.gz
mateusza
sumber
3
Solusi ini sangat baik dalam situasi di mana Anda bekerja dengan tarbal yang dibuat sebelum semua persyaratan Anda diketahui ...
Digger
2
Pikiran itu --strip-componentsadalah ekstensi GNU.
zneak
2
Jawaban ini dapat ditingkatkan dengan memberikan contoh "seperti biasa" dalam konteks.
Josh Habdas
33

Lihat --transform/ --xform, ini memberi Anda kesempatan untuk memijat nama file saat file ditambahkan ke arsip:

% 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

Transformasi ekspresi mirip dengan sed, dan kita dapat menggunakan pemisah selain /( ,dalam contoh di atas).
https://www.gnu.org/software/tar/manual/html_section/tar_52.html

Magnus
sumber
3
Saya akan melakukan ini. Ada lagi yang hanya retas!
jwg
2
Ini adalah solusi yang jauh lebih baik.
leesei
Ini solusi terbaik.
justhalf
1
Solusi yang bagus, tapi itu bisa menyebabkannya file list too long. Solusi saya mencegah itu dan lebih fleksibel juga.
aross
Ini solusi hebat. Anda juga dapat melewati --xformbeberapa kali untuk beberapa jalur.
syarat
26

TL; DR

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

Dengan beberapa kondisi (arsipkan hanya file, dir, dan symlink):

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

Penjelasan

Sayangnya di bawah ini termasuk direktori induk ./dalam arsip:

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

Anda dapat memindahkan semua file dari direktori itu dengan menggunakan --transformopsi konfigurasi, tetapi itu tidak menghilangkan .direktori itu sendiri. Menjadi semakin sulit untuk menjinakkan perintah.

Anda bisa menggunakan $(find ...)untuk menambahkan daftar file ke perintah (seperti dalam jawaban magnus ' ), tetapi itu berpotensi menyebabkan kesalahan "daftar file terlalu lama". Cara terbaik adalah menggabungkannya dengan -Topsi tar , seperti ini:

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

Pada dasarnya apa yang dilakukannya adalah mencantumkan semua file ( -type f), tautan ( -type l) dan subdirektori ( -type d) di bawah direktori Anda, buat semua nama file relatif menggunakan -printf "%P\n", dan kemudian sampaikan ke perintah tar (dibutuhkan nama file dari STDIN menggunakan -T -). The -Copsi diperlukan agar tar tahu di mana file dengan nama yang relatif berada. The --no-recursionbendera adalah agar tar tidak recurse ke folder itu diperintahkan untuk arsip (menyebabkan file duplikat).

Jika Anda perlu melakukan sesuatu yang istimewa dengan nama file (memfilter, mengikuti symlinks dll), findperintahnya cukup kuat, dan Anda dapat mengujinya dengan hanya menghapus tarbagian dari perintah di atas:

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

Misalnya jika Anda ingin memfilter file PDF, tambahkan ! -name '*.pdf'

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

Temuan non-GNU

Perintah ini menggunakan printf(tersedia di GNU find) yang memberitahu finduntuk mencetak hasilnya dengan jalur relatif. Namun, jika Anda tidak memiliki GNU find, ini berfungsi untuk membuat jalur relatif (menghilangkan orang tua dengan 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
sumber
2
Jawaban yang bagus Sangat rumit, dan yang paling penting, menyelesaikan masalah dengan sempurna.
Alex
16

Jawaban ini harus berfungsi dalam sebagian besar situasi. Namun perhatikan bagaimana nama file disimpan dalam file tar sebagai, misalnya, ./file1bukan hanya file1. Saya menemukan bahwa ini menyebabkan masalah ketika menggunakan metode ini untuk memanipulasi tarball yang digunakan sebagai file paket di BuildRoot .

Salah satu solusinya adalah menggunakan beberapa gumpalan Bash untuk mendaftar semua file kecuali untuk ..seperti ini:

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

Ini adalah trik yang saya pelajari dari jawaban ini .

Sekarang tar akan mengembalikan kesalahan jika tidak ada file yang cocok ..?*atau .[^.]*, tetapi masih akan berfungsi. Jika kesalahan adalah masalah (Anda memeriksa keberhasilan dalam skrip), ini berfungsi:

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

Meskipun sekarang kita mengotak-atik opsi shell, kita mungkin memutuskan bahwa lebih baik untuk *mencocokkan file tersembunyi:

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

Ini mungkin tidak berfungsi di mana shell Anda gumpal *di direktori saat ini, jadi alternatifnya, gunakan:

shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
Rob Fisher
sumber
1
Saya mendapatkan kesalahan aneh ketika saya melakukan ini. tar: start.sh: Cannot stat: No such file or directoryIni terjadi pada semua file di direktori saya saat ini! Bagaimana saya menghindari ini?
BrainStone
@BrainStone, saya mendapatkan hasil yang persis sama.
mbmast
15
cd my_directory
tar zcvf ../my_directory.tar.gz *
mateusza
sumber
2
Hal secara eksplisit bertanya tentang file tersembunyi. Kamu juga membutuhkan .??*.
PanCrit
2
-1: Ini tidak menambahkan file tersembunyi ke tar. Lihat jawaban tbman.
dubek
3

Jika ini adalah sistem Unix / Linux, dan Anda peduli tentang file tersembunyi (yang akan dilewatkan oleh *), Anda perlu melakukan:

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

Saya tidak tahu seperti apa file tersembunyi di bawah Windows.

PanCrit
sumber
2

Saya akan mengusulkan fungsi Bash berikut (argumen pertama adalah path ke dir, argumen kedua adalah nama file dari arsip yang dihasilkan):

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

Anda dapat menjalankannya dengan cara ini:

$ tar_dir_contents /path/to/some/dir my_archive

dan itu akan menghasilkan arsip my_archive.tar.gzdalam direktori saat ini. Ia bekerja dengan elemen tersembunyi (. *) Dan dengan elemen dengan spasi di nama file mereka.

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

Yang ini berfungsi untuk saya dan itu termasuk semua file tersembunyi tanpa meletakkan semua file di direktori root bernama "." seperti dalam jawaban tomoe :

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

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

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

Contoh:

tar.create folder

Sama sama.

mmm
sumber
1

Inilah yang bekerja untuk saya.

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

Anda juga bisa menggunakannya

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

Pada perintah pertama, find mengembalikan daftar file dan sub-direktori my_dir . Namun, direktori my_dir dengan sendirinya termasuk dalam daftar itu sebagai '.' The -printf parameter menghilangkan path lengkap termasuk yang '' dan juga semuanya Namun demikian dalam format string '% P' dari printf meninggalkan sisa dalam daftar file dan sub-direktori my_dir dan dapat dilihat oleh ruang terdepan di hasil perintah find .

Itu tidak akan menjadi masalah bagi TAR tetapi jika Anda ingin memperbaikinya, tambahkan -langkah 1 seperti pada perintah kedua.

serendrewpity
sumber
0

Gunakan pax.

Pax adalah paket usang tetapi melakukan pekerjaan dengan sempurna dan dengan cara yang sederhana.

pax -w > mydir.tar mydir
rjv
sumber
Paling praktis dan melakukan pekerjaan +1
Breno Salgado
perintah ini membuat mydir.tar dengan konten: mydir / file1 mydir / file2, persis apa yang harus dihindari.
Alex
0

Cara paling sederhana yang saya temukan:

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

alexgo
sumber
1
Itu tidak akan termasuk file tersembunyi.
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=-
}

Aman menangani nama file dengan spasi atau karakter tidak biasa lainnya. Anda bisa menambahkan -name '*.sql'filter atau sejenisnya ke perintah find untuk membatasi file yang disertakan.

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

Jika folder tersebut mytemp maka jika Anda menerapkan hal di atas akan zip dan menghapus semua file dalam folder tetapi biarkan saja

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

Anda dapat memberikan pola kecualikan dan juga menentukan untuk tidak melihat subfolder juga

pengguna1456599
sumber
-3
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`
mateusza
sumber