Que tal rm -r a*/*
? Isso deve resolver seu problema.
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).
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 {}/*
( 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
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
)