Как мне распаковать каталог файлов и папок, не включая сам каталог? - PullRequest
343 голосов
/ 02 июня 2009

Я обычно делаю:

tar -czvf my_directory.tar.gz my_directory

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

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

Я хочу:

my_file
my_file
my_file

Ответы [ 15 ]

594 голосов
/ 14 июня 2010

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

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

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

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

211 голосов
/ 03 июня 2009
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
51 голосов
/ 02 июня 2009

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

tar --strip-components 1 -xvf my_directory.tar.gz
31 голосов
/ 30 октября 2013

Посмотрите на --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

22 голосов
/ 16 сентября 2016

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 ...) для добавления списка файлов к команде (как в magnus 'answer ), но это может привести к ошибке «file list too long». Лучший способ - объединить его с опцией tar -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 необходима, чтобы tar знал, где находятся файлы с относительными именами. Флаг --no-recursion указывает на то, что tar не попадает в папки, которые ему сообщают в архив (вызывая дублирование файлов).

Если вам нужно сделать что-то особенное с именами файлов (фильтрация, последующие символические ссылки и т. Д.), Команда 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 -
16 голосов
/ 19 марта 2012

Этот ответ должен работать в большинстве ситуаций. Однако обратите внимание, как имена файлов хранятся в файле 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
15 голосов
/ 02 июня 2009
cd my_directory
tar zcvf ../my_directory.tar.gz *
3 голосов
/ 02 июня 2009

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

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

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

2 голосов
/ 27 февраля 2014

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

1 голос
/ 09 февраля 2017
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..

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

...