Eliminar los primeros n bytes de archivos

32

Tengo un problema extremo y todas las soluciones que puedo imaginar son complicadas. Según mi experiencia en UNIX / Linux, debe haber una manera fácil.

Quiero eliminar los primeros 31 bytes de cada archivo /foo/. Cada archivo es lo suficientemente largo. Bueno, estoy seguro de que alguien me entregará una solución sorprendentemente fácil que simplemente no puedo imaginar. Tal vez awk?

von der tann
fuente
2
Cualquier solución awk / sed / ed estará orientada a la línea, por lo que si no sabe que la primera línea tendrá al menos 31 caracteres, se producirán complicaciones.
Glenn Jackman

Respuestas:

28
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

o el más rápido, gracias a la sugerencia de Gilles:

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

Nota: La cola de Posix especifica "-c +32" en lugar de "+ 32c", pero a la cola predeterminada de Solaris no le gusta:

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

/usr/xpg4/bin/tail está bien con ambas sintaxis.

jlliagre
fuente
1
Sugerir ddaquí es excesivo, tailes más apropiado (más simple, menos riesgo de un error tipográfico asesino, no hay mensajes espurios en stderr).
Gilles 'SO- deja de ser malvado'
Tienes razón. Por lo general, evito los comandos destinados a procesar archivos de texto cuando se procesan posiblemente archivos binarios, pero "tail + 32c" funcionará aquí.
jlliagre
1
@jlliagre: Has escrito cut (¿no debería ser cola? ... asis, no me funciona ...
Peter.O
Por supuesto, es cola. Perdón por la falta de coincidencia.
jlliagre
@jlliagre: en Solaris, deberías tener /usr/xpg4/binventaja /usr/binsobre tu PATH, o te quedarás estancado a principios de la década de 1990. Muchas unidades (por ejemplo, GNU, BusyBox) ya no admiten la +32csintaxis histórica , y lo toman como un archivo llamado +32c(como requiere POSIX).
Gilles 'SO- deja de ser malvado'
12

Los siguientes comandos cortan los primeros 31 bytes $file(usando $file~como una copia temporal):

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

Solo necesita enumerar o findtodos los archivos debajo /foo/y ejecutar los dos anteriores para cada $fileencontrado.

alex
fuente
1
Intercambiar valores bs y skip aumentará el rendimiento.
jlliagre
10

tail -c +32genera su entrada menos los primeros 31 bytes. (Sí, el argumento está desactivado por uno.) Para editar un archivo en su lugar, use una esponja en un bucle, o si no lo tiene y no quiere molestarse, haga su trabajo en el 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

Si los comandos se interrumpen por cualquier motivo (por ejemplo, un corte de energía), puede ser difícil determinar dónde lo dejó. Escribir los nuevos archivos en un directorio separado facilitaría las cosas.

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

Si los archivos son realmente grandes (como en, lo suficientemente grandes como para que tener dos copias de una sola sea un problema), puede usar una de las técnicas mencionadas en este hilo .

Gilles 'SO- deja de ser malvado'
fuente
2

Puede usar Vim en modo Ex:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % seleccione todas las líneas

  2. ! ejecutar comando

  3. x guardar y cerrar

Steven Penny
fuente