Видаліть перші п байт файлів


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

чи швидше, завдяки пропозиції Джилса:

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

Примітка: Хвіст Posix вказує "-c +32" замість "+ 32c", але хвіст за замовчуванням Solaris не любить:

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

/usr/xpg4/bin/tail добре з обома синтаксисами.


1
Запропонувати ddтут надмірно, tailє більш доречним (простіший, менший ризик помилки вбивці, відсутні помилкові повідомлення про stderr).
Жил "ТАК - перестань бути злим"

Ти правий. Зазвичай я уникаю команд, призначених для обробки текстових файлів при обробці можливо бінарних файлів, але тут працює «хвіст + 32c».
jlliagre

1
@jlliagre: Ви написали cut (чи не повинен це бути хвіст? ... Асіс, це не працює для мене ...
Peter.O

Звичайно, це хвіст. Вибачте за невідповідність.
jlliagre

@jlliagre: Що стосується Solaris, ви повинні /usr/xpg4/binвипереджати /usr/binсвої дії PATH, інакше ви застряжете на початку 1990-х. Багато уніцій (наприклад, GNU, BusyBox) більше не підтримують історичний +32cсинтаксис, і вважають це файлом, який називається +32c(як вимагає POSIX).
Жил "ТАК - перестань бути злим"

12

Наступні команди вирізають перші 31 байт з $file(використовуючи $file~як темп. Копію):

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

Вам потрібно лише перелічити findвсі файли під /foo/та виконати два вище для кожного $fileзнайденого.


1
Заміна bs і пропуск значень підвищить продуктивність.
jlliagre

10

tail -c +32виводить свій вхід мінус перші 31 байт. (Так, аргумент вимкнено одним.) Щоб редагувати файл на місці, використовуйте губку в циклі, або якщо у вас її немає і не хочете турбувати, виконайте свою роботу в оболонці:

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

Якщо файли дійсно великі (як, наприклад, досить великі, що наявність двох копій навіть однієї є проблемою), ви можете використовувати один із прийомів, згаданих у цій темі .


2

Ви можете використовувати Vim в режимі Ex:

for each in /foo/*
do
  ex -sc '%!tail -c+32' -cx "$each"
done
  1. % виберіть усі рядки

  2. ! запустити команду

  3. x зберегти і закрити

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.