Як я орієнтуюся на каталог файлів і папок, не включаючи сам каталог?


382

Я зазвичай роблю:

tar -czvf my_directory.tar.gz my_directory

Що робити, якщо я просто хочу включити все (включаючи всі приховані системні файли) у my_directory, але не сам каталог? Я не хочу:

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

Мені потрібно:

my_file
my_file
my_file

Це поведінка за замовчуванням робити tar -czf? У моєму випадку це зберігання лише файлів, а не каталогу. Коли я просто tarкаталог, він включає його, але до tar -czfнього додається лише файли.
Durga Swaroop

Відповіді:


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

повинні виконувати роботу в один рядок. Він добре працює і для прихованих файлів. "*" не розширює приховані файли шляхом розширення імені шляху принаймні в bash. Нижче мій експеримент:

$ 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
Це також буде працювати з файлами з пробілами або іншими спеціальними символами. Хороша робота!
PanCrit

29
Не ідеально - файл tar містить "." а також ./file1 замість просто file1. Мені подобається рішення від mateusza нижче, щоб використовувати --strip-компоненти під час скасування.
Іван

23
@Ivan, якщо ви заміните .на *так, команда буде, cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..то вона буде працювати, як ви очікували.
Анонім

3
@jmathew Ви також можете скористатись нижньою оболонкою, щоб робоча директорія вашої поточної оболонки не змінювалася:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Алек

Я знаю, що це стара відповідь, але cdвказівки в каталоги та вихідні дуже кульгаві. Міг би принаймні використовувати, pushdі popdякщо tarне було подібних прапорів -C.
Андріс

667

Використовуйте -Cперемикач дьогтю:

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

-C my_directoryКаже дьоготь для зміни поточного каталогу my_directory, а потім .означає «додати весь поточний каталог» ( в тому числі прихованих файлів і підкаталогів).

Переконайтеся, що ви робите, -C my_directoryперш ніж це зробити, .інакше ви отримаєте файли в поточному каталозі.


5
+1 дякую! Це був чорт '. Я пропав безвісти. настільки обтяжуюче
JCotton

14
« В відміну від більшості варіантів, -C обробляється в точці це відбувається в списку файлів, що підлягають обробці Розглянемо наступну команду :. tar --create --file=foo.tar -C /etc passwd hosts -C /lib libc.a» Apl.jhu.edu/Misc/Unix-info/tar/tar_65.html Я завжди намагаюся tar -czvf my_directory.tar.gz * -C my_directoryі це не працює. -Cмісце важливе! Чорт дьоготь ...
m-ric

57
Не ідеально - файл tar містить "." а також ./file1 замість просто file1. Мені подобається рішення від mateusza нижче, щоб використовувати --strip-компоненти під час скасування.
Іван

3
@ Superole: оболонка замінює подвійні символи перед запуском дьогтю. Також зауважте, що використання символів підстановки *не включатиме приховані файли (що було початковою вимогою).
дубек

28
Це створює. як кореневий каталог у .tar.gz.
Анонім

59

Ви також можете створити архів, як зазвичай, і витягнути його за допомогою:

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

3
Це рішення особливо добре в тих ситуаціях, коли ви працюєте з таргами, створеними до того, як всі ваші вимоги були відомі ...
Digger

2
Розум, --strip-componentsце розширення GNU.
zneak

2
Цю відповідь можна покращити, подавши приклад «як завжди».
Джош Хабдас

33

Погляньте на --transform/ --xform, це дає вам можливість масажувати назву файлу, коли файл додається до архіву:

% 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

Вираз трансформації аналогічний експресії sed, і ми можемо використовувати роздільники, окрім /( ,у наведеному вище прикладі).
https://www.gnu.org/software/tar/manual/html_section/tar_52.html


3
Я б це зробив. Все інше - просто хак!
jwg

2
Це набагато краще рішення.
leesei

Це найкраще рішення.
justhalf

1
Гарне рішення, але це може спричинити file list too long. Моє рішення запобігає цьому і є більш гнучким.
1717

Це чудове рішення. Ви також можете пройти --xformкілька разів для кількох шляхів.
elig

26

TL; DR

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

З деякими умовами (архівуйте лише файли, файли та посилання):

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

Пояснення

Нижченаведене, на жаль, містить батьківський каталог ./в архіві:

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

Ви можете перемістити всі файли з цього каталогу за допомогою параметра --transformконфігурації, але це не позбудеться самого .каталогу. Приборкувати команду стає все важче.

Ви можете використати $(find ...)для додавання списку файлів до команди (наприклад, у відповіді магнуса ), але це потенційно спричиняє помилку "список файлів занадто довгий". Найкращий спосіб - це поєднувати його з -Tваріантом дьогтю , як це:

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

В основному, це те, що перелічити всі файли ( -type f), посилання ( -type l) та підкаталоги ( -type d) у вашому каталозі, зробити всі назви файлів відносно за допомогою -printf "%P\n", а потім передати їх команді tar (для отримання файлів STDIN використовує назви файлів -T -). -CОпція необхідна , так дьоготь знає , де файли з відносними іменами розташовані. --no-recursionПрапор так , щоб смола НЕ рекурсії в папки Розповідаються в архів (породження дублікатів файлів).

Якщо вам потрібно зробити щось особливе з назви файлів (фільтрування, наступні символьні посилання тощо), findкоманда досить потужна, і ви можете перевірити її, просто видаливши tarчастину вищевказаної команди:

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

Наприклад, якщо ви хочете відфільтрувати файли PDF, додайте ! -name '*.pdf'

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

Знахідка, що не належить до GNU

Команда використовує printf(доступна в GNU find), яка повідомляє findдрукувати її результати відносними шляхами. Однак якщо у вас немає GNU find, це допомагає зробити шляхи відносними (видаляє батьків із 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
Чудова відповідь. Дуже продумано, а головне, ідеально вирішує проблему.
Олексій

16

Ця відповідь має працювати в більшості ситуацій. Однак зауважте, як назви файлів зберігаються у файлі tar, наприклад, ./file1а не просто file1. Я виявив, що це спричинило проблеми під час використання цього методу для маніпулювання тарболами, що використовуються як файли пакетів у BuildRoot .

Одним з варіантів є використання деяких глобусів Bash, щоб перелічити всі файли, крім ..такого:

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

Це хитрість, яку я дізнався з цієї відповіді .

Тепер дьоготь повертає помилку , якщо є файли не відповідають ..?*або .[^.]*, але він все одно буде працювати. Якщо помилка є проблемою (ви перевіряєте успіх у сценарії), це працює:

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

Хоча зараз ми псуємось із параметрами оболонки, ми можемо вирішити, що акуратніше мати *приховані файли:

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

Це може не працювати там, де ваші оболонки глобусу *в поточному каталозі, тому в якості альтернативи використовуйте:

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

1
Я отримую помилкові помилки, коли це роблю. tar: start.sh: Cannot stat: No such file or directoryЦе відбувається з усіма файлами в моєму поточному каталозі! Як я цього уникаю?
BrainStone

@BrainStone Я отримую точно такі ж результати.
mbmast

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

2
Хал явно запитав про приховані файли. Вам також потрібно. ?? *.
PanCrit

2
-1: Це не додає приховані файли в тар. Дивіться відповідь tbman.
дубек

3

Якщо це система Unix / Linux, і ви дбаєте про приховані файли (які будуть пропущені *), вам потрібно зробити:

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

Я не знаю, як виглядають приховані файли під Windows.


2

Я б запропонував наступну функцію Bash (перший аргумент - це шлях до dir, другий аргумент - базове ім'я результуючого архіву):

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

Ви можете запустити його таким чином:

$ tar_dir_contents /path/to/some/dir my_archive

і він створить архів my_archive.tar.gzу поточному каталозі. Він працює із прихованими (. *) Елементами та з елементами з пробілами у назви файлу.


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

Цей працював для мене, і він включає всі приховані файли без розміщення всіх файлів у кореневій директорії з назвою "." як у відповіді tomoe :


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

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

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

Приклад:

tar.create folder

Будь ласка.


1

Це те, що працює для мене.

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

Ви також можете використовувати

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

У першій команді знайдіть повертає список файлів і підкаталогів my_dir . Однак сам каталог my_dir включений у цей список як "." The -printf видаляє повний шлях, включаючи цей '. а також усі Однак в рядку формату «% Р» з PRINTF залишає залишку в списку файлів і підкаталогів my_dir і можна побачити на провідних просторі в результаті знаходять команди.

Це не буде проблемою для TAR, але якщо ви хочете виправити це, додайте -mindepth 1, як у другій команді.


0

Використовуйте pax.

Pax є застарілим пакетом, але виконує цю роботу ідеально та просто.

pax -w > mydir.tar mydir

Найпрактичніше та виконує завдання +1
Брено Салгадо

ця команда створює mydir.tar із вмістом: mydir / file1 mydir / file2, саме того, чого слід уникати.
Олексій


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

Безпечно обробляє назви файлів з пробілами або іншими незвичайними символами. Ви можете додатково додати в -name '*.sql'команду find або подібний фільтр для обмеження включених файлів.


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

Якщо папка - mytemp, тоді, якщо ви застосуєте вище, вона зафіксує та видалить усі файли в папці, але залиште її в спокої

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

Ви можете надати шаблони виключення, а також вказати, щоб також не дивитись у папки


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.