ファイルの最初のnバイトを削除します


32

私には極端な問題があり、想像できるすべての解決策は複雑です。私のUNIX / Linuxの経験によると、簡単な方法が必要です。

の各ファイルの最初の31バイトを削除したい/foo/。各ファイルは十分な長さです。まあ、誰かが私に想像を絶する驚くほど簡単な解決策を提供してくれると確信しています。たぶんawk?


2
awk / sed / edのソリューションはいずれも行指向であるため、最初の行が少なくとも31文字になることがわからない場合は複雑になります。
グレンジャックマン

回答:


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の提案のおかげで:

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

注:Posixの末尾は、「+ 32c」ではなく「-c +32」を指定しますが、Solarisのデフォルトの末尾はこれを好みません。

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

/usr/xpg4/bin/tail 両方の構文で問題ありません。


1
ddここで提案するのは過剰でtailあり、より適切です(より単純で、キラータイプミスのリスクが少なく、stderrに偽のメッセージがありません)。
ジル 'SO-悪であるのをやめる'

あなたが正しいです。通常、バイナリファイルを処理するときにテキストファイルを処理することを意図したコマンドは避けますが、ここでは "tail + 32c"が機能します。
jlliagre

1
@jlliagre:あなたは書いたcut (それは尻尾ではないだろうか?...そのまま、それは私にはうまくいかない
...-Peter.O

もちろん、それは尾です。不一致については申し訳ありません。
jlliagre

@jlliagre:Solarisの場合は、あなたが持っている必要があります/usr/xpg4/bin先の/usr/binあなたにPATH、またはあなたが1990年代初頭に立ち往生することがあります。多くのユニックス(GNU、BusyBoxなど)は、歴史的な+32c構文をサポートしなくなりました+32c(POSIXが要求するように)と呼ばれるファイルを意味します。
ジル 'SO-悪であるのをやめる'

12

次のコマンドは、最初の31バイトをカットします$file$file~一時コピーとして使用):

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

あなたはfindすべてのファイルをリストするか、すべてのファイルを見つけて/foo/実行する必要があります$file


1
bsとskipの値を交換すると、パフォーマンスが向上します。
jlliagre

10

tail -c +32入力から最初の31バイトを引いた値を出力します。(はい、引数は1つずれています。)ファイルを所定の場所で編集するには、スポンジをループで使用します。または、ファイルがなくて気にしたくない場合は、シェルでその作業を行います。

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

何らかの理由(停電など)でコマンドが中断された場合、中断した場所を特定するのは困難です。新しいファイルを別のディレクトリに書き込むと、作業が簡単になります。

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

ファイルが非常に大きい場合(たとえば、1つでも2つのコピーが存在することが問題になるほど大きい場合)、このスレッドで説明されている手法のいずれかを使用できます


2

ExモードでVimを使用できます。

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % すべての行を選択

  2. ! コマンドを実行する

  3. x 保存して閉じます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.