paulo1205
(usa Ubuntu)
Enviado em 10/05/2018 - 14:52h
slackjeff escreveu:
Vamos usar algo bem simples
for files in $(ls DIRETORIOPRINCIPAL): do
[[ ! -e "DIRETORIOCONFERIR/$files" ]] && cp "$files" "DIRETORIOCONFERIR"
done
Fazendo assim, você
• se atrapalha se houver arquivos contendo espaços, tabulações e outros caracteres especiais no nome,
• corre o risco de usar uma quantidade absurda de memória (se o diretório tiver muitos arquivos),
• esqueceu de colocar “
DIRETORIOPRINCIPAL ” no nome do arquivo origem para o comando
cp (a cópia vai falhar, a não ser que o processo execute dentro do diretório de origem),
• usa um nome no plural (
files ) para se referir a um único arquivo.
Para corrigir o primeiro erro, esqueça a chamada de
ls dentro da expansão de comandos. Seria melhor uma expansão de nomes de arquivos feita pelo próprio
shell .
for file in DIRETORIOPRINCIPAL/*; do
: bla, bla, bla...
done
Mas isso ainda tem o inconveniente de gastar memória do
shell no caso de haver muitos arquivos.
Para evitar o gasto de memória, pode-se usar um redirecionamento a partir da saída de um comando externo que gere a lista de arquivos (e que, além disso, tome cuidado de não se embaralhar com nomes de arquivos que podem conter espaços, quebras de linhas e outros caracteres complicados; requer uma versão recente do Bash).
# Redirecionamento feito para o descritor 3.
exec 3< <(find DIRETORIOPRINCIPAL -mindepth 1 -maxdepth 1 -print0)
while read -u 3 -d $'\0' file; do
: bla, bla, bla...
done
exec 3<&- # Libera o descritor 3.
A forma acima coloca o nome de um arquivo de cada vez na variável
file , mas tal nome vem com o caminho completo (“
DIRETORIOPRINCIPAL/xxxx ”).
Você poderia invocar o comando
basename para remover a parte contendo o diretório, mas chamar um comando externo dentro de um laço de repetição é uma operação custosa e, portanto, que é melhor ser evitada. Felizmente, podemos usar a funcionalidade de extração de
substring do Bash.
base="${file#DIRETORIOPRINCIPAL/}" # Remove o texto “DIRETORIOPRINCIPAL/” do início da expansão de ${file}. ou
base="${file:21}" # 21 é o comprimento do texto “DIRETORIOPRINCIPAL/”, que é pulado na expansão de ${file}.
Então, uma forma relativamente eficiente (na medida em que o
shell permite) de copiar os arquivos do diretório
X e que não existam no diretório
Z para um diretório
Y seria a seguinte.
#!/bin/bash
srcdir="X"
dstdir="Y"
tstdir="Z"
declare -i srclen
srclen=${#srcdir}+1 # +1 é por causa da barra ('/') que vai aparacer após o nome do diretório.
exec 3< <(find X -mindepth 1 -maxdepth 1 -type f -print0)
while read -u 3 -d $'\0' file; do
base="${file:$srclen}"
[[ -f "$tstdir/$base" ]] || cp -p "$file" "$dstdir/$base"
done
exec 3<&-