Supprimer les n premiers octets de fichiers

32

J'ai un problème extrême et toutes les solutions que je peux imaginer sont compliquées. Selon mon expérience UNIX / Linux, il doit exister un moyen simple.

Je souhaite supprimer les 31 premiers octets de chaque fichier au format /foo/. Chaque fichier est assez long. Eh bien, je suis sûr que quelqu'un me proposera une solution étonnamment facile que je ne peux tout simplement pas imaginer. Peut-être awk?

von der tann
la source
2
Toute solution awk / sed / ed sera orientée ligne, donc si vous ne savez pas que la première ligne aura au moins 31 caractères, des complications s'ensuivront.
Glenn Jackman

Réponses:

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

ou le plus rapide, grâce à la suggestion de Gilles:

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

Remarque: La queue Posix spécifie "-c +32" au lieu de "+ 32c" mais la queue par défaut de Solaris ne l'aime pas:

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

/usr/xpg4/bin/tail va bien avec les deux syntaxes.

jlliagre
la source
1
Suggérer ddici est excessif, tailc'est plus approprié (plus simple, moins de risque de faute de frappe, pas de messages parasites sur stderr).
Gilles, arrête de faire le mal
Vous avez raison. J'évite généralement les commandes destinées à traiter des fichiers texte lors du traitement de fichiers éventuellement binaires, mais "tail + 32c" fonctionnera ici.
Juin
1
@jlliagre: Vous avez écrit cut ? (ne devrait pas que la queue soit ... ASIS, il ne fonctionne pas pour moi ...
Peter.O
Bien sûr, c'est la queue. Désolé pour le décalage.
Juin
@jlliagre: Sur Solaris, vous devriez avoir à l' /usr/xpg4/binavance /usr/binsur votre PATHou vous serez coincé au début des années 1990. De nombreux unices (GNU, BusyBox, par exemple) ne supportent plus la +32csyntaxe d' historique et le considèrent comme un fichier appelé +32c(comme le requiert POSIX).
Gilles, arrête de faire le mal
12

Les commandes suivantes coupent les 31 premiers octets de $file(en utilisant $file~une copie temporaire):

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

Il vous suffit de répertorier ou de répertorier findtous les fichiers situés sous /foo/et d’exécuter les deux opérations ci-dessus pour chaque fichier $filetrouvé.

alex
la source
1
L'échange de valeurs bs et skip augmentera les performances.
Juillet
10

tail -c +32sort son entrée moins les 31 premiers octets. (Oui, l'argument est décalé de un.) Pour éditer un fichier à la place, utilisez sponge dans une boucle ou, si vous ne l'avez pas et ne voulez pas vous déranger, faites son travail dans le 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 les commandes sont interrompues pour une raison quelconque (par exemple, une panne de courant), il peut être difficile de déterminer où vous en êtes resté. L'écriture des nouveaux fichiers dans un répertoire séparé faciliterait les choses.

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 les fichiers sont vraiment volumineux (comme dans, assez gros pour avoir deux copies d'un seul problème, vous pouvez utiliser l' une des techniques mentionnées dans ce fil de discussion .

Gilles, arrête de faire le mal
la source
2

Vous pouvez utiliser Vim en mode Ex:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % sélectionner toutes les lignes

  2. ! commande d'exécution

  3. x sauver et fermer

Steven Penny
la source