Como posso tar um diretório de arquivos e pastas sem incluir o próprio diretório?
Pergunta
Eu normalmente fazer:
tar -czvf my_directory.tar.gz my_directory
E se eu só quero incluir tudo (incluindo quaisquer arquivos de sistema ocultos) em my_directory, mas não o próprio diretório? Eu não quero:
my_directory
--- my_file
--- my_file
--- my_file
Eu quero:
my_file
my_file
my_file
Solução
cd my_directory/ && tar -zcvf ../my_dir.tgz . && cd -
deve fazer o trabalho em uma linha. Ele funciona bem para arquivos ocultos também. "*" Não expande arquivos escondidos por expansão nome do caminho, pelo menos em bash. Abaixo está a minha experiência:
$ 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
Outras dicas
Use o interruptor -C
de alcatrão:
tar -czvf my_directory.tar.gz -C my_directory .
O -C my_directory
diz tar para alterar o diretório atual para my_directory
, e depois meio .
"adicionar o diretório atual inteira" (incluindo arquivos ocultos e sub-diretórios).
Certifique-se de fazer -C my_directory
antes de fazer .
ou então você vai obter os arquivos no diretório atual.
Você também pode criar arquivo como de costume e extraí-lo com:
tar --strip-components 1 -xvf my_directory.tar.gz
Tenha um olhar em --transform
/ --xform
, dá-lhe a oportunidade de massagear o nome do arquivo como o arquivo é adicionado ao arquivo:
% 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
Transform expressão é semelhante ao de sed
, e podemos usar diferentes /
separadores (,
no exemplo acima).
https://www.gnu.org/software/tar/manual/html_section /tar_52.html
TL; DR
find /my/dir/ -printf "%P\n" | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
Com algumas condições (arquivar apenas arquivos, diretórios e links simbólicos):
find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
Explicação
A seguir, infelizmente, inclui um ./
diretório pai no arquivo:
tar -czf mydir.tgz -C /my/dir .
Você pode mover todos os arquivos fora desse diretório usando a opção de configuração --transform
, mas isso não se livrar do diretório .
si. Torna-se cada vez mais difícil de domar o comando.
Você pode usar $(find ...)
para adicionar uma lista de arquivos para o comando (como em magnus' resposta ), mas que potencialmente provoca uma "lista de arquivo muito longo" erro. A melhor maneira é combiná-lo com a opção -T
de alcatrão, como este:
find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d | tar -czf mydir.tgz --no-recursion -C /my/dir/ -T -
Basicamente o que ele faz é listar todos os arquivos (-type f
), links (-type l
) e subdiretórios (-type d
) sob seu diretório, fazer todos os nomes de arquivos relativa utilizando -printf "%P\n"
, e, em seguida, passar isso para o comando tar (leva nomes de arquivos a partir de STDIN usando -T -
). A opção -C
é necessário para tar sabe onde estão os arquivos com nomes relativos estão localizados. A bandeira --no-recursion
é para que o alcatrão não recurse em pastas que é dito para arquivo (causando arquivos duplicados).
Se você precisa fazer algo especial com nomes de arquivos (filtragem, seguintes links simbólicos, etc), o comando find
é muito poderoso, e você pode testá-lo por apenas removendo a parte tar
do comando acima:
$ find /my/dir/ -printf "%P\n" -type f -o -type l -o -type d
> textfile.txt
> documentation.pdf
> subfolder2
> subfolder
> subfolder/.gitignore
Por exemplo, se você quiser arquivos PDF de filtro, adicione ! -name '*.pdf'
$ find /my/dir/ -printf "%P\n" -type f ! -name '*.pdf' -o -type l -o -type d
> textfile.txt
> subfolder2
> subfolder
> subfolder/.gitignore
Não-GNU encontrar
O comando usa printf
(disponível em GNU find
) que diz find
para imprimir seus resultados com caminhos relativos. No entanto, se você não tem GNU find
, isso funciona para fazer os caminhos relativos (remove pais com 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 -
Este Resposta deve funcionar na maioria das situações. Aviso no entanto como os nomes de arquivos são armazenados no arquivo tar como, por exemplo, ./file1
ao invés de apenas file1
. Descobri que este problemas causados ??quando usar este método para manipular tarballs usados ??como arquivos de pacotes em BuildRoot .
Uma solução é usar algum Bash globs para listar todos os arquivos exceto para ..
assim:
tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
Este é um truque que aprendi com esta resposta .
Agora tar retornará um erro se não há arquivos ..?*
ou .[^.]*
correspondentes, mas ainda vai funcionar. Se o erro é um problema (que está a verificar para o sucesso em um script), isso funciona:
shopt -s nullglob
tar -C my_dir -zcvf my_dir.tar.gz .[^.]* ..?* *
shopt -u nullglob
Embora agora estamos mexendo com opções de shell, que pode decidir que é mais puro que ter jogo *
arquivos escondidos:
shopt -s dotglob
tar -C my_dir -zcvf my_dir.tar.gz *
shopt -u dotglob
Este pode não funcionar onde seu shell globs *
no diretório atual, então, alternativamente, use:
shopt -s dotglob
cd my_dir
tar -zcvf ../my_dir.tar.gz *
cd ..
shopt -u dotglob
cd my_directory
tar zcvf ../my_directory.tar.gz *
Se é um sistema Unix / Linux, e você se preocupa com arquivos ocultos (que não será atingido por *), você precisa fazer:
cd my_directory
tar zcvf ../my_directory.tar.gz * .??*
Eu não sei o que arquivos escondidos olhar como no Windows.
Eu proporia a seguinte função Bash (primeiro argumento é o caminho para a dir, segundo argumento é o nome base resultante de arquivo):
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"
}
Você pode executá-lo da seguinte maneira:
$ tar_dir_contents /path/to/some/dir my_archive
e vai gerar o my_archive.tar.gz
arquivo dentro do diretório atual. Ele funciona com oculto (. *) Elementos e com elementos com espaços em seu nome.
cd my_directory && tar -czvf ../my_directory.tar.gz $(ls -A) && cd ..
Este trabalhou para mim e é incluir todos os arquivos ocultos, sem colocar todos os arquivos em um diretório raiz com o nome "" como em de Tomoe resposta :
Use pax.
Pax é um pacote obsoleto, mas faz o trabalho perfeitamente e de forma simples.
pax -w > mydir.tar mydir
Mais simples maneira que eu encontrei:
cd meu_diretório && tar -czvf ../my_dir.tar.gz *
# 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=-
}
segurança lida com nomes de arquivos com espaços ou outros caracteres incomuns. Opcionalmente, é possível adicionar um -name '*.sql'
ou filtro semelhante ao comando find para limitar os arquivos incluídos.
tar -cvzf tarlearn.tar.gz --remove-files mytemp/*
Se a pasta é mytemp em seguida, se você aplicar o que precede, vai zip e remover todos os arquivos na pasta, mas deixá-lo sozinho
tar -cvzf tarlearn.tar.gz --remove-files --exclude='*12_2008*' --no-recursion mytemp/*
Você pode dar excluir padrões e também especificar para não olhar em subpastas demasiado
tar -C my_dir -zcvf my_dir.tar.gz `ls my_dir`