Exclui os primeiros n bytes de arquivos

27

Eu tenho um problema extremo, e todas as soluções que posso imaginar são complicadas. De acordo com minha experiência com UNIX / Linux, deve ser uma maneira fácil.

Desejo excluir os primeiros 31 bytes de cada arquivo em /foo/ . Cada arquivo é longo o suficiente. Bem, tenho certeza que alguém me entregará uma solução surpreendentemente fácil que eu simplesmente não consigo imaginar. Talvez awk?

    
por von der tann 27.05.2011 / 17:00

4 respostas

23
for file in /foo/*
do
  if [ -f "$file" ]
  then
    dd if="$file" of="$file.truncated" bs=31 skip=1 && mv "$file.truncated" "$file"
  fi
done

ou mais rápido, graças à sugestão de Gilles:

for file in /foo/*
    do
      if [ -f $file ]
      then
        tail +32c $file > $file.truncated && mv $file.truncated $file
      fi
    done

Nota: Posix tail especifica "-c +32" em vez de "+ 32c" mas a cauda padrão do Solaris não gosta:

   $ /usr/bin/tail -c +32 /tmp/foo > /tmp/foo1
    tail: cannot open input

/usr/xpg4/bin/tail está bem em ambas as sintaxes.

    
por 27.05.2011 / 17:20
12

Os seguintes comandos cortam os primeiros 31 bytes de $file (usando $file~ como uma cópia temporária):

dd if="$file" of="$file~" bs=1 skip=31
mv "$file~" "$file"

Você só precisa listar ou find todos os arquivos em /foo/ e executar os dois acima para cada $file encontrado.

    
por 27.05.2011 / 17:19
10

tail -c +32 exibe sua entrada menos os primeiros 31 bytes. (Sim, o argumento está desativado em um.) Para editar um arquivo, use esponja em um loop, ou se você não tem e não quer se incomodar, faça o seu trabalho no shell:

for x in /foo/*; do tail -c +32 "$x" | sponge "$x"; done
for x in /foo/*; do tail -c +32 "$x" >"$x.new" && mv "$x.new" "$x"; done

Se os comandos forem interrompidos por qualquer motivo (por exemplo, uma falha de energia), pode ser difícil descobrir de onde você parou. Escrever os novos arquivos em um diretório separado facilitaria as coisas.

mkdir /foo.tmp
cd /foo
for x in *; do tail -c +42 -- "$x" >"/foo.tmp/$x" && rm -- "$x"; done
mv /foo.tmp/* /foo
rmdir /foo.tmp

Se os arquivos forem realmente grandes (por exemplo, grandes o suficiente para que duas cópias de um único seja um problema), você pode usar uma das técnicas mencionadas neste tópico .

    
por 28.05.2011 / 00:14
0

Você pode usar o Vim no modo Ex:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % seleciona todas as linhas

  2. ! comando de execução

  3. x salvar e fechar

por 11.04.2016 / 05:03