encontre xargs rm com padrão de nome de arquivo na variável

encontre xargs rm com padrão de nome de arquivo na variável

Comando assim:

find /directory -type f -name "*.txt" -print | xargs rm

exclua todos .txtos 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 .txtarquivos 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 *.txtpadrã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 finda string literal *.txt, assim:

pattern='*.txt'
find /directory -type f -name "$pattern" -exec rm {} +

Aqui, também me livrei xargs rme estou executando rmdiretamente do find. A maioria das implementações atuais findpoderia usar o não padrão -deleteno 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 findiniciar.

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 /directoryhouvesse uma grande hierarquia de diretórios. O código a seguir faz isso criando uma série de -nametestes para finduso:

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 .tmpem qualquer lugar dentro ou abaixo do diretório /directory.

informação relacionada