Как мне распаковать каталог файлов и папок, не включая сам каталог?

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
l'L'л
источник
Это поведение по умолчанию tar -czf? В моем случае это только хранение файлов, а не каталог. Когда я просто tarкаталог, он включает его, но с tar -czfним только добавление файлов.
Дурга Сваруп

Ответы:

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-components при удалении тарифов.
Иван
23
@Ivan, если вы замените .на *так, команда будет, cd my_directory/ && tar -zcvf ../my_dir.tgz * && cd ..тогда она будет работать, как вы ожидали.
Аноним
3
@jmathew Вы также можете использовать подоболочку так рабочий каталог вашей текущей оболочки не меняется:$ (cd my_directory/ && tar -zcvf ../my_dir.tgz .)
Alec
Я знаю, что это старый ответ, но cdвходить в каталоги и выходить довольно неубедительно. Мог бы по крайней мере использовать, pushdи popdесли tarне было никаких флагов, как -C.
Андрис
668

Используйте -Cпереключатель tar:

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

Команда -C my_directorytar сообщает об изменении текущего каталога my_directory, а затем .означает «добавить весь текущий каталог» (включая скрытые файлы и подкаталоги).

Убедитесь, что вы делаете, -C my_directoryпрежде чем вы делаете, .иначе вы получите файлы в текущем каталоге.

Дюбек
источник
5
+1 спасибо! Это был проклятый ". Я скучал. так
обидно
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местоположение важно! Черт возьми ...
М-рик
57
Не идеально - файл tar содержит '.' а также ./file1 вместо просто file1. Мне нравится решение mateusza, приведенное ниже, для использования --strip-components при удалении тарифов.
Иван
3
@Superole: оболочка заменяет символы подстановки перед запуском tar. Также обратите внимание, что использование символа подстановки *не будет включать скрытые файлы (что было первоначальным требованием).
Дубек
28
Это создает . в качестве корневого каталога в .tar.gz.
Аноним
59

Вы также можете создать архив как обычно и распаковать его:

tar --strip-components 1 -xvf my_directory.tar.gz
mateusza
источник
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

Выражение преобразования аналогично выражению of sed, и мы можем использовать разделители, отличные от /( ,в приведенном выше примере).
https://www.gnu.org/software/tar/manual/html_section/tar_52.html

Магнус
источник
3
Я бы сделал это. Все остальное просто взломать!
JWG
2
Это гораздо лучшее решение.
leesei
Это лучшее решение.
полугодие
1
Хорошее решение, но оно может вызвать file list too long. Мое решение предотвращает это и является более гибким.
aross
Это отличное решение. Вы также можете пройти --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опцией 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 -

По сути, он выводит список всех файлов ( -type f), links ( -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 -
aross
источник
2
Отличный ответ. Очень продуманно, а главное, отлично решает проблему.
Алекс
16

Этот ответ должен работать в большинстве ситуаций. Обратите внимание, однако, как имена файлов хранятся в файле tar как, например, ./file1а не просто file1. Я обнаружил, что это вызывает проблемы при использовании этого метода для манипулирования тарболами, используемыми в качестве файлов пакетов в BuildRoot .

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

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

Это трюк, который я узнал из этого ответа .

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

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 *
mateusza
источник
2
Хэл явно спросил о скрытых файлах. Тебе тоже нужно. ?? *.
PanCrit
2
-1: Это не добавляет скрытые файлы в tar. Смотрите ответ tbman.
Дубек
3

Если это система Unix / Linux, и вы заботитесь о скрытых файлах (которые будут пропущены *), вам нужно сделать:

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

Я не знаю, как выглядят скрытые файлы под Windows.

PanCrit
источник
2

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

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в текущем каталоге. Он работает со скрытыми (. *) Элементами и с элементами с пробелами в имени файла.

gpz500
источник
2
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

Этот работал для меня, и он включает все скрытые файлы, не помещая все файлы в корневой каталог с именем "." как в ответе Томоэ :

мед
источник
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 ')

В первой команде find возвращает список файлов и подкаталогов my_dir . Однако каталог my_dir сам по себе включен в этот список как «.» -printf удаляет полный путь, включая этот «.» а также все Однако в строке формата «% Р» из PRINTF оставляет остатка в списке файлов и подкаталогов my_dir и можно увидеть на ведущих пространстве в результате находят команды.

Это не будет проблемой для TAR, но если вы хотите это исправить, добавьте -mindepth 1, как во второй команде.

serendrewpity
источник
0

Пакс.

Pax - устаревший пакет, но делает работу отлично и просто.

pax -w > mydir.tar mydir
RJV
источник
Наиболее практичен и выполняет свою работу +1
Брено Сальгадо
эта команда создает mydir.tar с содержимым: mydir / file1 mydir / file2, именно то, чего следует избегать.
Алекс
0

Самый простой способ, который я нашел:

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

alexgo
источник
1
Это не будет включать скрытые файлы.
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=-
}

Безопасно обрабатывает имена файлов с пробелами или другими необычными символами. При желании вы можете добавить -name '*.sql'или подобный фильтр к команде поиска, чтобы ограничить количество включаемых файлов.

marcingo
источник
-1
 tar -cvzf  tarlearn.tar.gz --remove-files mytemp/*

Если папка mytemp, то, если вы примените вышеизложенное, она заархивирует и удалит все файлы в папке, но оставит ее в покое.

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

Вы можете задать шаблоны исключений, а также указать, что не следует просматривать вложенные папки.

user1456599
источник