Xargs e rm com um *

4

Estou tentando executar o seguinte comando

ls -d a* | xargs -i sudo rm -rf {}/*

O problema é que quando eu adiciono a parte /* , o comando não funciona. Eu quero remover o conteúdo do diretório (não o próprio diretório).

    
por Lombo 30.12.2010 / 16:07

4 respostas

7

Que tal rm -r a*/* ? Isso deve resolver seu problema.

    
por 30.12.2010 / 16:24
5

Comandos como rm dependem do shell para expandir os curingas, então você precisa invocar um shell em algum lugar.

Talvez

 ls -d a* | xargs -i sh -c sudo rm -rf {}/*
    
por 30.12.2010 / 16:20
1

( Aviso : eu não testei nenhum desses comandos. Pode haver erros de digitação ou erros. Tente tudo com echo ou ls e não sudo primeiro. )

Recomendação geral: xargs raramente é a maneira mais simples de fazer alguma coisa. Sem -i (que é obsoleto, use o portable -I {} ), xargs espera um formato de entrada que nenhuma ferramenta padrão ou comum produz. Com -I , xargs tem algum uso, mas se você estiver canalizando find para ele, find -exec será mais simples.

Você precisa de um shell para expandir {}/* e esse shell deve agir após {} ter sido substituído por um caminho real. Uma solução simples é fazer o processamento linha por linha no shell. Observe o uso de três padrões para capturar todos os arquivos em um diretório, pois * omite arquivos de ponto; Não importa se alguns dos padrões não correspondem a nenhum arquivo, pois rm -f ignora qualquer argumento que não faça referência a um arquivo existente.

… |
while read -r line; do
  sudo rm -rf -- "$line"/* "$line"/.[!.]* "$line"/..?*
done

O Xargs não é usado aqui, já que você precisa processar os arquivos um por um de qualquer maneira, a fim de fazer com que o shell realize a globbing. No entanto, como a técnica geral pode ser útil, aqui está uma maneira de enviar nomes de arquivos de volta para um shell a partir do xargs. O _ é o argumento $0 para o shell (é necessário, em parte, incomodar-se em colocar $0 em qualquer argumento subsequente e garantir que tudo funcione mesmo se $1 começar com - e assim seriam tratados como uma opção para o shell). Existem duas abordagens aqui: ou ter o loop do shell sobre seus argumentos, ou dizer ao xargs para passar um único argumento para cada invocação do shell.

… | xargs -I {} sudo sh -c 'for x; do rm -rf -- "$x"/* "$x"/.[!.]* "$x"/..?*; done' _ {}
… | xargs -I {} -n 1 sudo sh -c 'rm -rf -- "$1"/* "$1"/.[!.]* "$1"/..?*' _ {}

Suponho que ls -d a* seja um exemplo de brinquedo e que você tenha um comando mais complexo que produza um nome de arquivo por linha. Observe que ls -d a* não funcionará lá, pois a maioria das implementações ls não exibe caracteres não imprimíveis de forma transparente. Se o for um comando find, use -exec , como em

find a* -exec sh -c 'rm -rf -- "$1"/* "$1"/.[!.]* "$1"/..?*' _ {} \; -prune
    
por 30.12.2010 / 16:59
0

Outra opção é usar um loop de shell em vez de invocar xargs.

E.G.

ls -d a* | while read dir; do sudo rm -rf "$dir"/*; done;

Principalmente por exemplo, você também pode combinar as duas técnicas colocando uma construção shell no meio de um pipeline:

ls -d a* | while read dir; do ls -d "$dir"/*; done | xargs -d \n rm -rf

A opção -d para xargs apenas especifica que o delimitador entre os argumentos é uma nova linha, o que evita problemas potencialmente catastróficos com nomes de arquivos que contêm espaços (por exemplo deadly / file )

    
por 31.12.2010 / 09:00

Tags