Найкращий спосіб видалити байти з початку файлу?


61

Сьогодні мені довелося видалити перші 1131 байт із змішаного текстового / двійкового файлу потужністю 800 Мб, відфільтрований дамп підривної роботи, який я хакую для нового сховища. Який найкращий спосіб зробити це?

Для початку я спробував

dd bs=1 skip=1131 if=filtered.dump of=trimmed.dump

але після пропуску це копіюється залишок файлу за один раз, тобто дуже повільно. Врешті-решт я опрацював, мені було потрібно 405 байт, щоб округлити це до трьох блоків 512, які я міг пропустити

dd if=/dev/zero of=405zeros bs=1 count=405
cat 405zeros filtered.dump | dd bs=512 skip=3 of=trimmed.dump

який завершився досить швидко, але, мабуть, був простіший / кращий спосіб? Чи є ще один інструмент, про який я забув? Дякую!


ddє правильним інструментом для роботи - схоже, ви придумали приємне, елегантне рішення вашої проблеми.
Джастін Етьє

Відповіді:


62

Ви можете перемикати bs та пропускати параметри:

dd bs=1131 skip=1 if=filtered.dump of=trimmed.dump

Таким чином операція може отримати вигоду від більшого блоку.

В іншому випадку ви можете спробувати з хвостом (хоча використовувати його з бінарними файлами не безпечно):

tail -c +1132 filtered.dump >trimmed.dump

Нарешті, ви можете використовувати 3 екземпляри dd, щоб написати щось подібне:

dd if=filtered.dump bs=512k | { dd bs=1131 count=1 of=/dev/null; dd bs=512k of=trimmed.dump; }

де перший dd друкує стандартний вихід filtered.dump; другий просто читає 1131 байт і викидає їх; потім останній зчитує зі свого стандартного вводу решта байтів filtered.dump і записує їх у trimmed.dump.


6
Дякую! Я не знав, що трубопровідна передача переноситься на такий другий процес - це дуже акуратно. Я не можу повірити, що я не думав про це bs=1131 skip=1: - /
Rup

2
Більшість сучасних реалізацій утиліти оболонки працюють правильно з бінарними файлами (тобто вони не мають проблем з нульовими символами і не вставляють зайвий новий рядок в кінці файлу). Звичайно, реалізація GNU та * BSD є безпечною.
Жил

17

Не впевнений, коли skip_bytesдодано, але для пропуску перших 11 байтів у вас є:

# echo {123456789}-abcdefgh- | 
                              dd bs=4096 skip=11 iflag=skip_bytes
-abcdefgh-
0+1 records in
0+1 records out
11 bytes (11 B) copied, 6.963e-05 s, 158 kB/s

Де iflag=skip_bytesDD каже інтерпретувати значення для skipпараметра як байти замість блоків, роблячи це просто.


Звичайно швидкість переваги великих файлів та невеликої кількості даних, які потрібно видалити.
sstn

Це найкраща відповідь, оскільки він працює для кожного розміру блоку, наприкладiflag=skip_bytes skip=1234 bs=1M
phiresky

15

Ви можете використовувати підрозділ і два ddдзвінки, як це:

$ ( dd bs=1131 count=1 of=dev_null && dd bs=4K of=out.mp3 ) < 100827_MR029_LobbyControl.mp3
1+0 records in
1+0 records out
1131 bytes (1.1 kB) copied, 7.9691e-05 s, 14.2 MB/s
22433+1 records in
22433+1 records out
91886130 bytes (92 MB) copied, 0.329823 s, 279 MB/s
$ ls -l *
-rw------- 1 max users 91887261 2011-02-03 22:59 100827_MR029_LobbyControl.mp3
-rw-r--r-- 1 max users     1131 2011-02-03 23:04 dev_null
-rw-r--r-- 1 max users 91886130 2011-02-03 23:04 out.mp3
$ cat dev_null out.mp3 > orig
$ cmp 100827_MR029_LobbyControl.mp3 orig

1
Дякую - я не знав, що трубопровідний вхід продовжував такий другий процес, як, напевно, це додаткова оболонка? Я обов'язково пам’ятаю це! Я дав Марко галочку, тому що він першим потрапив сюди, але +1 і дякую за відповідь!
Rup

1
@Rup, так, підрозділ - створений через круглі дужки - забезпечує дескриптор файлу stdin, і обидва DD дзвінки послідовно споживають вхід з нього. Так - Марко побив мене за 29 секунд :)
maxschlepzig

6

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

$ fallocate <magic> -o 0 -l 1131 inplace.dump

де <magic>залежить від файлової системи, версії Linux та типу файлу ( FALLOC_FL_COLLAPSE_RANGEабо FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZEйого можна використовувати внутрішньо ).


1
Це мій кращий метод, але запуск цього в контейнері має свої проблеми. stackoverflow.com/questions/31155591/…
michaelcurry

3

Ви повинні використовувати count=0- це просто, lseek()коли це можливо.

Подобається це:

{  dd bs=1131 skip=1 count=0; cat; } <filtered.dump >trimmed.dump

ddбуде lseek()вхідний файл дескриптора на 1131 байта зі зміщенням, а потім catпросто скопіювати всі , що залишається на виході.


2

Ще один спосіб , щоб видалити провідні байти з файлу (без використання ddвзагалі) полягає в використанні xxdі sedчи tailвідповідно.

bytes=$((1131*2))

xxd -p -c 256 filtered.dump | tr -d '\n' | sed "s/^.\{0,${bytes}\}//" | xxd -r -p > trimmed.dump

bytes=$((bytes + 1)) 
xxd -p -c 256 filtered.dump | tr -d '\n' | tail -c +${bytes} | xxd -r -p > trimmed.dump

Це акуратно, але я думаю, що я вважаю за краще просто працювати з файлом у двійковому форматі, а не перетворювати його в шістнадцятковий.
Rup

2

@maxschlepzig запитує онлайн-лайнер. Ось один в перл. Потрібно 2 аргументи: Від байту та довжини. Вхідний файл повинен бути заданий символом '<', а вихід буде на stdout:

perl -e 'sysseek(STDIN,shift,0) || die; $left = shift;
     while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){
        $left -= $read; syswrite(STDOUT,$buf);
     }' 12345678901 19876543212 < bigfile > outfile

Якщо довжина більша за файл, решта файлу буде скопійована.

У моїй системі цей показник забезпечує 3,5 Гб / с.


Я думаю, що його однолінійним завданням було змусити вас довести, що рішення мови сценаріїв було краще, ніж його однолінійне рішення оболонки. І я віддаю перевагу його: мені це коротше і зрозуміліше. Якщо ваш працює краще, це тому, що ви використовуєте більший розмір блоку, ніж він, який також легко збільшується в його версії.
Rup

@Rup На жаль, але ні. Ви, здається, забуваєте, що ddне гарантує повного читання. Спробуйте: так | dd bs = кількість 1024k = 10 | wc unix.stackexchange.com/questions/17295/…
Ole Tange

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