Por que sua tentativa falhou e como corrigi-la
Você pode acumular uma lista de nomes de arquivos retornados por find
, mas somente se não houver novas linhas em nomes de arquivos, e você precisa tomar precauções.
Quando você escreve uma substituição de comando sem aspas ou expansão variável, como $LISTOFFILES
aqui, o shell executa divisão de palavras e globbing (expansão de wildcard) no resultado.
Regra: sempre coloque aspas duplas em torno de substituições de comandos e expansões de variáveis.
Exceção: se você entender por que precisa deixar as aspas duplas e por que é seguro fazê-lo.
Aqui, você precisa deixar as aspas duplas, porque a divisão de palavras é o que divide a string em bits separados por nova linha. Mas, por padrão, ele também se divide em outros caracteres de espaço em branco. Então você precisa fazer isso seguro e desligar também. Você realiza o primeiro configurando a IFS
variable para uma única nova linha e a última invocando set -f
.
IFS='
'
set -f
tar cvf backup.tar $LISTOFFILES
Observe que não há barras invertidas envolvidas. Barras invertidas são usadas quando você insere nomes de arquivos diretamente, não quando são produzidos por comandos como find
.
A maneira usual de usar find
Em vez de analisar a saída de find
, você deve fazer com que invoque o comando que deseja executar nos arquivos, por meio da ação -exec
. Isso cuida do caso em que há tantos arquivos que o tamanho máximo da linha de comando é excedido: o programa é invocado tantos quantos forem necessários.
Aqui, isso é um pouco difícil, porque você não pode invocar tar -c
várias vezes (seria iniciado novamente a partir de um novo arquivo vazio em cada chamada). Mas veja Preencha todos os PDFs em um diretório, mantendo a estrutura de diretório
Métodos mais fáceis
Se não houver muitos arquivos, e você estiver executando ksh93 ou bash ≥4 ou zsh, use o curinga **
para recorrer a subdiretórios. Você precisa definir algumas opções de shell primeiro:
set -o globstar # on ksh93
shopt -s globstar -s extglob # on bash 4
setopt ksh_glob # on zsh
tar cvf backup.tar ~/**/*.@(PDF|pdf|ODT|odt)
No zsh, sem configurações específicas, você pode escrever esse padrão como ~/**/*.(PDF|pdf|ODT|odt)
. Depois de setopt extglob
, você pode escrevê-lo como ~/**/(#i)*.(pdf|odt)
.
Ou você pode usar pax :
pax -w -x ustar -s '/\.pdf$/&/' -s '/\.PDF$/&/' -s '/\.odt$/&/' -s '/\.ODT$/&/' -s '/.*//' ~ >backup.tar
Se você não quiser o prefixo do caminho
Existem maneiras com tar
e pax
, mas a abordagem mais simples é mudar para o diretório que você deseja arquivar primeiro.
( IFS='
'; set -f; cd ~ && tar cvf /path/to/backup.tar $(find . …) )
( cd ~ && pax -w … . ) >backup.tar