Comando assim:
find /directory -type f -name "*.txt" -print | xargs rm
exclua todos .txt
os arquivos do diretório e subdiretórios e tudo bem. Mas, se criarmos uma variável ou array para extensão de arquivo e depois colocarmos find
, por exemplo,
TXT=(*.txt)
for ii in ${TXT[@]}; do
find /directory -type f -name $TXT -print | xargs rm
done
esses comandos não excluem .txt
arquivos em subdiretórios. Por que? Como alterar esse segundo código para deletar arquivos em subdiretórios?
PS: Usei um array, pois tenho mais de uma extensão de arquivo.
Responder1
Sua atribuição de matriz,
TXT=(*.txt)
expandirá o *.txt
padrão para a lista de nomes de arquivos no diretório atual que corresponde a esse padrão. O shell faria isso no momento da atribuição. Isto não é o que você quer. Você deseja fornecer find
a string literal *.txt
, assim:
pattern='*.txt'
find /directory -type f -name "$pattern" -exec rm {} +
Aqui, também me livrei xargs rm
e estou executando rm
diretamente do find
. A maioria das implementações atuais find
poderia usar o não padrão -delete
no lugar de -exec rm {} +
:
pattern='*.txt'
find /directory -type f -name "$pattern" -delete
Observe que não há necessidade de loop aqui, pois estamos lidando apenas com um único padrão. Observe também que a citação de "$pattern"
na chamada to find
é importante, caso contrário, o padrão seria substituído por todos os nomes de arquivos correspondentes no diretório atual antes de find
iniciar.
Para vários padrões, você poderia fazer um loop assim:
patterns=( '*.txt' '*.tmp' )
for pattern in "${patterns[@]}"; do
find /directory -type f -name "$pattern" -delete
done
A citação na atribuição do array é essencial, pois impede que o shell use os padrões como padrões globbing de nome de arquivo naquele momento. A citação de "${patterns[@]}"
e "$pattern"
é igualmente importante, pela mesma razão.
Outra abordagem é fazer apenas uma chamada para find
, mesmo se você tiver vários padrões. Isso aceleraria um pouco as coisas se /directory
houvesse uma grande hierarquia de diretórios. O código a seguir faz isso criando uma série de -name
testes para find
uso:
patterns=( '*.txt' '*.tmp' )
name_tests=( )
for pattern in "${patterns[@]}"; do
name_tests+=( -o -name "$pattern" )
done
# "${name_tests[@]:1}" removes the initial "-o", which shouldn't be there.
name_tests=( '(' "${name_tests[@]:1}" ')' )
find /directory -type f "${name_tests[@]}" -delete
No script acima, o comando real executado no final será
find /directory -type f '(' -name '*.txt' -o -name '*.tmp' ')' -delete
... que excluirá todos os arquivos regulares que possuem sufixos de nome de arquivo.txt
ou .tmp
em qualquer lugar dentro ou abaixo do diretório /directory
.