xargs argumento redirecionamento

4

Este parece ser um problema trivial, mas a solução me ilude com tanta cautela.

Eu quero limpar muitos arquivos de texto; arquivos de log. Razão? Para economizar espaço em disco.

Com um arquivo de texto, isso é tão trivial quanto echo '' > path/to/file.txt

No entanto, os arquivos são muitos. Eu usei find e xargs . Mas eu não sei como contornar "redirecionamento de entrada" .

Eu tentei find . -name <regex> | xargs -I target echo '' > target e echo '' > { find . -name <regex> | xargs -I target target } ; nenhum funcionou

Eu não sou bem versado em scripts de shell, qualquer ajuda é apreciada.

Obrigado.

    
por iGbanam 26.07.2012 / 07:01

3 respostas

9

O que você fez em ambos os exemplos é colocar o > onde o shell atual pode vê-lo, então o redirecionamento está sendo feito apenas uma vez, antes que os comandos find e xargs sejam executados. Esse é o seu primeiro problema.

Seu segundo problema é que, se você citar o > para que ele seja passado para xargs , ele ainda não funcionará porque xargs não passa seu comando por meio de um shell, a menos que você o solicite.

Seu terceiro problema é que se você disser ao xargs para usar um shell para executar o comando, o shell fará a coisa errada se algum nome de arquivo contiver caracteres engraçados. (Também xargs faz a coisa errada com personagens engraçados em si, mas isso pode ser corrigido com -0 .)

Outros problemas, com os quais você talvez não se importe, incluem:

  • echo '' não cria um arquivo vazio, mas um arquivo que contém uma nova linha.
  • a opção -name usa glob e não regex.
  • talvez você queira adicionar -type f apenas no caso de qualquer diretório corresponder ao glob.

Aqui está uma versão parcialmente corrigida do comando:

find . -name '*thisisaglob*' -type f -print0 |
xargs -0 -I target sh -c ': > target'

Isso corrige a maioria dos problemas que mencionei. Ainda permanece o problema do shell interpretar erroneamente um nome de arquivo contendo metacaracteres de shell. Para corrigir isso, você teria que dar o nome do arquivo ao shell como um parâmetro em vez de como parte do comando -c . Isso ficaria assim:

find . -name '*thisisaglob*' -type f -print0 |
xargs -0 -I target sh -c ': > "$1"' fnord target

O "fnord" é um marcador de posição. Torna-se $0 do qual não precisamos.

Agora que atingimos o objetivo de usar o xargs e o redirecionamento juntos com segurança, mostrarei como alcançar seu objetivo usando nenhum deles.

find . -name '*thisisaglob*' -type f -exec truncate -s 0 '{}' +

Isso requer o comando truncate , que é parte do GNU coreutils e não um utilitário padrão do unix, por isso é menos portável, mas muito mais fácil de ler, não é?

    
por 26.07.2012 / 07:29
2

Enquanto a resposta de Alan Curry é completa, precisa e muito bem informada, tenho uma pergunta. Por que você quer que os arquivos continuem existindo, mesmo vazios?

Minha recomendação natural seria:

find . -name <glob> -print0 | xargs -0 rm

Se você precisasse que os arquivos existissem por algum motivo, você poderia fazer uma série de comandos:

find . -name <glob> -print0 | tee /tmp/filelist | xargs -0 rm
cat /tmp/filelist | xargs -0 touch

Se você simplesmente quisesse compactar os arquivos (por exemplo, se eles fossem principalmente informações redundantes / repetitivas, mas você quisesse economizar espaço e manter os arquivos), tente:

find . -name <glob> -print0 | xargs -0 tar -xzf /tmp/logfiles.tgz
    
por 26.07.2012 / 07:43
0

Se você tem o link do GNU Paralelo instalado, você pode fazer isso:

find . -name '*thisisaglob*' -type f | parallel '>'

Você pode instalar o GNU Parallel simplesmente por:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem

Assista aos vídeos de introdução do GNU Parallel para saber mais: link

    
por 30.07.2012 / 22:08