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


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.