Як витягти байти з середини файлу?


1

Ми аналізуємо кілька великих файлів EDI, які не містять CR / LF. Однак вони ~( тильда ) є розділювачем сегменту.

Я намагаюся витягнути контрольний запис для файлу, а останні байти мого 120 МБ файлу виглядають приблизно так:

~REF*1L*0711882~SE*62300*39093~GE*1*500001242~IEA*1*500001241~

У файлі є лише одна контрольна запис, і вона завжди починається з ~SE.

Отже, чи є простий спосіб за допомогою стандартних інструментів вирізати Unix , awk , grep та ін., Щоб вирізати цей файл, щоб отримати сегмент SE * 62300 * 39093, окрім конвертації у ~CRLF та підключення останніх трьох рядків файлу?

Відмова:
Я не гуру Unix, тому відповідь може бути очевидною для досвідченого користувача. Також я не контролюю формат файлу.


Що не так у перетворенні ~на нові рядки та підключенні останніх 3 рядків файлу. Якщо файл, як відомо, ще не містить нових рядків, то це не вносить неоднозначності у формат, і відверто кажучи, це найкращий спосіб масажувати файл у форматі, який спрощує роботу всіх цих лінійних інструментів.
— Селада

@Celada: Я не людина Unix, але перетворення сотень мегабайт для вилучення останніх 100 або більше символів просто здається завищеним; Деякі з цих файлів можуть бути дуже великими, і я шукаю найпростіший спосіб зробити це.
— Ной

Ви можете відфільтрувати до кількох останніх рядків файлу, використовуючи tail. Не потрібно все це розбирати. Щось на зразок tail edi_file | grep ~SE | cut -d'~' -f 3(де edi_file - назва вашого великого файлу) (Відмова: Приклад працює лише у тому випадку, якщо потрібне поле знаходиться у полі №3 (розмежоване на ~ s як -d ~. Це може знадобитися коригування. Чи можемо ми отримати більший розмір Приклад вхідного файлу
— Hennes

120MB не такий великий. Ніхто ніколи не турбувався про те, щоб видалити кожен останній шматочок із сценарію оболонки. Якщо ви цього хочете, використовуйте C :-) Отже, відповідь Майкла Коне - це те, що я б робив. Або якщо файл дійсно занадто великий, щоб ви хотіли прочитати все, попередньо відфільтруйте його чимось на кшталт tail --bytes=5000 ding... і тоді ви сподіваєтесь, що останніх 5000 байтів вистачить, щоб охопити 3 потрібні рядки.
— Селада

За один раз річ. Я згоден. Нехай біжить. Щось, що використовується щодня, мені подобається лише розбирати хвіст. І тому, що це не марно і тому, що просто непотрібно марно витрачати. (Не те, що намагатися знайти відповідь протягом 20 хвилин - не марно. Хоча немає варіанту - байти в BSD).
— Геннес

Відповіді:


3

Це можна зробити за допомогою:
tr "~" "\n" < edi_file | tail -20 | grep ^SE

Tr tr відповідає всім тильдам до нових рядків. (Вони представлені символом \ n).

Потім результат його подається в хвіст, який відкидає всі, крім останніх 20 рядків.

Напевно, ви можете точно налаштувати це, залежно від того, що ви хочете шукати. Без цього весь файл подається в grep, що, ймовірно, набагато більш ресурсомістке, ніж хвіст. Якщо у вас є конкретна версія хвоста, яка підтримує показ частини файлу на байтах, а не в рядках, ви можете скористатися цим кроком раніше.

Я не вибрав цей варіант, оскільки ваша публікація позначена загальним unix, а не сучасним Linux з сучасними інструментами GNU та специфічними розширеннями GNU .

Нарешті grepфільтрує кінцеві рядки до тих, що містять SE, і carret ( ^) гарантує, що він знаходиться на початку на рядку. (Попередження таких речей, як ~ foooo SE foobarquz ~ SE wewantthispartonly ~ boobar ~ для показу двох рядків).


4

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

Для цього слід зробити фокус:

cat ding | tr "~" "\n" | tail -3

Це не найефективніша річ у Всесвіті, але навіть у 120-мегабайтному файлі запускати не слід.

Зверніть увагу, що лапки в двох наборах необов’язкові - обидва, ~і вони \nбудуть інтерпретовані оболонкою, якщо ви кинете цитати.


3
tr "~" "\n" < edi_file | tail -20 | grep ^SE? (Не потрібно використовувати, catколи дані можна переспрямовувати. Греп показувати лише поля, починаючи з SE.
— Hennes

@Hennes: Це простіша відповідь, чи можете ви додати її, і я прийму. Що я в кінцевому підсумку використав - tr "~" "\ n" <edi_file | хвіст -3 | head -n 1 Однак це лише тому, що я знаю, що SE завжди є третім за останнім сегментом
— Ной

Зроблено. Знання конкретного формату даних допомагає. Я додав ще кілька пояснень до публікації нижче та до причини, чому я використав це.
— Hennes

2

Спочатку це буде неефективно для великих файлів tr, оскільки ви насправді хочете дані з кінця і trобробляєте дані, які будуть викинуті.

Використовуйте tacдля читання файлу в зворотному порядку, а потім візьміть 20 перших рядків (зворотного, фактично останнього), знову поверніть назад, щоб отримати оригінальний порядок, зараз grep:

tac -s~ edi_file | head -n 20 | tac | grep ^SE

Пам'ятайте, що ви не seek()можете трубу!


1
Ви хочете цитувати ~ символів - залежно від оболонки, одинокий ~ може розширитися в щось.
— Майкл Коне

@MichaelKohne: Так. Але здається, що tacперетвориться на нові рядки, тому trне потрібно
— Janus Troelsen

@ysangkok: Можливо, ви пропустили пункт про те, що у файлі є лише 1 рядок.
— Ной

@Noah: Тому я використовую -sпрапор дляtac
— Janus Troelsen

@ysangkok: Я не тегував питання solaris, тому що не думав, що це буде мати значення. Але виявляється, що tac не підтримується під Solaris. Я підтримав вашу відповідь, тому що я дізнався щось нове, і, схоже, він би працював на інших системах * nx
— Ноя
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.