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


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.