
Estou tentando escrever um script para copiar arquivos recursivamente de uma pasta específica A.extn
, exceto files B/*.extn
e C/*
onde B
e C
são diretórios e extn
é apenas uma extensão genérica. Isto é o que eu tenho:
#!/usr/local/bin/zsh
setopt EXTENDED_GLOB
TMPDIR=/tmp/test
cp -pR $(dirname $0)/**~(*.foo/*|*/bar.txt|*.abc|qux.txt) $TMPDIR
No entanto, isso não nega o padrão conforme o esperado. Acho que sei por quê - embora o padrão esteja correto (como visto em echo
), cp -R
não está ciente do padrão e entra em um diretório que "não deveria" e, uma vez lá, o padrão não é mais válido.
Como modifico o acima para fazer o que quero? Eu acho que é possível com find
and xargs
, mas estou atraído pela clareza do que foi dito acima e preferiria algo semelhante (mas se for a maneira errada de fazer isso, ficaria perfeitamente feliz com uma solução diferente).
Responder1
Você está certo de que o padrão é expandido antes de cp
ser executado, portanto, é desconhecido para esse comando.
Você pode conseguir o que deseja usando a --parents
opção em cp
vez de -R
. Isso copiará apenas os arquivos que correspondem ao seu padrão, mas usará o nome completo do caminho fornecido, em vez de apenas o nome do arquivo final.
Mas esta opção não é portátil. AFAIK, é suportado apenas pela versão GNU do cp.
Responder2
Seu padrão pode excluir os arquivos que você não deseja copiar, mas não exclui os diretórios que os contêm, e você disse cp
para copiar recursivamente. Portanto, os arquivos são copiados de qualquer maneira. Pior que isso, se você tiver uma árvore de origem como
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
então o padrão se expande foo hello hello/world hello/world/wibble.txt
para que você tenha esses arquivos em $TMPDIR
:
foo
foo/bar.txt
hello
hello/world
hello/world/wibble.txt
wibble.txt
world
world/wibble.txt
Isso não tem nada a ver com o padrão “não ser mais válido”. O padrão é expandido pelo shell, cp
só vê a lista de arquivos.
Você precisa usar uma ferramenta de cópia que possa excluir arquivos enquanto faz a travessia recursiva.
Você pode usar o zcp para isso, mas ele não copiará os diretórios e não criará diretórios de destino automaticamente. A ferramenta mais fácil para este trabalho é o rsync. Pax é outra opção.
rsync -a --exclude='*.foo/*' --exclude='bar.txt' --exclude='*.abc' --exclude='/qux.txt' $(dirname $0) $TMPDIR