Dosyaların ilk n baytını sil


32

Aşırı bir sorunum var ve hayal edebileceğim tüm çözümler karmaşık. UNIX / Linux deneyimime göre kolay bir yol olmalı .

Her dosyanın ilk 31 baytını silmek istiyorum /foo/. Her dosya yeterince uzun. Birinin bana hayal bile edemediğim şaşırtıcı derecede kolay bir çözüm sunacağından eminim. Belki awk?


2
Herhangi bir awk / sed / ed çözümü satır yönelimli olacaktır, bu nedenle ilk satırın en az 31 karakter olacağını bilmiyorsanız komplikasyonlar ortaya çıkar.
glenn jackman

Yanıtlar:


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

Gilles'un önerisi sayesinde daha hızlı:

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

Not: Posix kuyruğu "+ 32c" yerine "-c +32" belirtir, ancak Solaris varsayılan kuyruğu bundan hoşlanmaz:

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

/usr/xpg4/bin/tail Her iki sözdizimi ile iyi.


1
Önerme dd, overkill burada tail(stderr daha basit bir katil yazım hatası az riski, hiç sahte mesajlar) daha uygundur.
Gilles 'SO- kötülük'

Haklısın. Muhtemelen ikili dosyaları işlerken metin dosyalarını işlemeyi amaçlayan komutlardan kaçınıyorum ama "tail + 32c" burada çalışacak.
jlliagre

1
@jlliagre: Sen yazdın cut (bu kuyruk olmamalı mı? ... asis, benim için işe yaramıyor ...
Peter.O

Tabii ki, bu kuyruk. Uyumsuzluk için üzgünüm.
jlliagre

@jlliagre: Solaris üzerinde, olması gereken /usr/xpg4/binilerisinde /usr/binsizinle ilgili şu PATHveya 1990'ların başında sıkışmış olacak. Birçok birim (örneğin GNU, BusyBox) artık tarihsel +32csözdizimini desteklememektedir ve bunu (POSIX'in +32cgerektirdiği şekilde) adı verilen bir dosyaya götürmektedir .
Gilles 'SO- kötülük' dur '28

12

Aşağıdaki komutlar ilk 31 baytı $file( $file~geçici kopya olarak kullanarak) keser :

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

findTüm bulunanlar /foo/için sadece altındaki tüm dosyaları listelemeniz ve yukarıdaki ikisini çalıştırmanız yeterlidir $file.


1
Bs ile değerlerin atlanması performansı artıracaktır.
jlliagre

10

tail -c +32ilk 31 baytı eksi girişiyle çıkarır. (Evet, bağımsız değişken birer birer kapalıdır.) Bir dosyayı yerinde düzenlemek için bir döngüde sünger kullanın ya da istemiyorsanız ve rahatsız etmek istemiyorsanız, işini kabukta yapın:

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

Komutlar herhangi bir nedenden ötürü kesilirse (örn. Elektrik kesintisi), kaldığınız yeri bulmak zor olabilir. Yeni dosyaları ayrı bir dizine yazmak işleri kolaylaştırır.

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

Dosyalar gerçekten büyükse (olduğu gibi, tek bir tane bile iki kopyasına sahip olmak bir problemdir), bu iş parçasında bahsedilen tekniklerden birini kullanabilirsiniz .


2

Vim'i Ex modunda kullanabilirsiniz:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % tüm satırları seç

  2. ! run komutu

  3. x kaydet ve kapat

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.