LINUX.ORG.RU

Awk для работы с групами строк

 , ,


0

1

Насколько я осилил сабж - он жрет по строке за раз. Есть ли какой нибудь тул для обработки текста группами строк. Что то, что позволило бы записать код для обработки текста в виде:

group-pattern{ //Нашли начало группы
   for-string-pattern1 { // преобразование для первого типа строк 
    // на выходе получаем одну или более строк
   }

   for-string-pattern2 { // преобразование для второго типа строк
   }

   sub-group-pattern {
     ...
   }
} // Больше нет совпадений для шаблонов учавствующих в этой группе и её подгруппах

Мэй би я ниасилил и такие вещи можно делать комбинируя grep:awk:sed?

★★★★★

Давай говорить предметно.
Для этого нужен пример входных и выходных данных, да

zolden ★★★★★
()

В AWK можно указать свои разделители для строк (читай, «записей»), делается встроенной переменной RS.

Ещё в AWK есть range patterns, которые состоят из двух паттернов через запятую, например, FNR > 10, $5 > 30 будет матчиться для всех записей, начиная с 10 в файле и заканчивая той, у которой в 5й колонке будет значение больше 30.

yoghurt ★★★★★
()

у меня стояла как-то задача в awk обрабатывать группы строк, решал с пом. команды awk - getline. но наверное это говнокод

bl ★★★
()

Я ничего не понял, но видимо

/pattern0/ || /pattern1/ || /pattern2/ {
  if (/pattern0/) {
    ...
  }

  if (/pattern1/) {
    ...
  }

  if (/pattern2/) {
    ...
  }
}
kim-roader ★★
()
Ответ на: комментарий от sdio

По большому счёту да, интересует, какие средства имеются для того что бы решать задачи этого класса над текстовыми файлами.

По просьбам выше пример входных и выходных данных:

Input.txt:

typedef uint32_t SomeType;

//some doc here
const SomeType val1 = 1;
//some doc here
//and additional doc
const SomeType val2 = 2;
...
const SomeType valn = n;

Ouptut.txt:

[::System::Flags]
public enum class SomeType : System::UInt32
{
    /// <summary> some doc here </summary>
    const SomeType val1 = 1,
    
    /// <summary>
    /// some doc here
    /// and additional doc
    /// </summary>
    const SomeType val2 = 2,
    ...
    const SomeType valn = n
};

Можно конечно было бы как то пристегнуть в данном конкретном случае clang, но пока хочется попробовать обойтись без него.

pon4ik ★★★★★
() автор топика
Ответ на: комментарий от pon4ik

И как Input.txt: коррелирует с исходным сообщением?

sdio ★★★★★
()
Ответ на: комментарий от pon4ik

Как правильно замечено выше таки описания как одно соотносится с другим нет. А это просто решение в стиле машины состояний.

/^\/\// {
  if (num) {
    if (num == 1) {
      print "\t/// <summary>"
      print "\t/" buffer
    }
    print "\t/" $0
    num++;
  } else {
    num = 1; buffer = $0;
  }
  next;
}

{
  if (num) {
    if (num == 1) {
      print "\t/// <summary> " buffer " </summary>"
    } else {
      print "\t/// </summary>"
    }
  }
  num = 0;
  print "\t" $0
}

Обычно генерирую несколько больше шаблонов (/xixi/ && num == 1) дабы не использовать лишние if. Красивости (пробелы, корректная обработка конца файла) легко добавить. И никто не мешает использовать большие массивы, функции (чтобы не повторять одинаковый код) и т.п.

io ★★
()

Прочитав этот тред я вдруг понял, почему на собеседованиях, когда я говорил, что «Мне не нужен перл, я пишу на баш и сед», встречал то круглые глаза, то непонимающе-снисходительные.

deterenkelt
()

ВНЕЗАПНО: это и есть awk. Оно работает с _записями_, и запись==строка только по умолчанию.

File: gawk.info, Node: Records, Next: Fields, Up: Reading Files

4.1 How Input Is Split into Records ===================================

The `awk' utility divides the input for your `awk' program into records and fields. `awk' keeps track of the number of records that have been read so far from the current input file. This value is stored in a built-in variable called `FNR'. It is reset to zero when a new file is started. Another built-in variable, `NR', records the total number of input records read so far from all data files. It starts at zero, but is never automatically reset to zero.

Records are separated by a character called the «record separator». By default, the record separator is the newline character. This is why records are, by default, single lines. A different character can be used for the record separator by assigning the character to the built-in variable `RS'.

emulek
()
Ответ на: комментарий от beastie

а при чём тут awk?

$ echo "ABC
AAA
XXX
DDD
BBB
DDD
CCC
AAA
DDD
BBB" | sed -n '/AAA/,/BBB/p'
AAA
XXX
DDD
BBB
AAA
DDD
BBB

emulek
()
Ответ на: комментарий от deterenkelt

Прочитав этот тред я вдруг понял, почему на собеседованиях, когда я говорил, что «Мне не нужен перл, я пишу на баш и сед», встречал то круглые глаза, то непонимающе-снисходительные.

кстати, почему?

(если что, я тоже пишу на баш и сед)

emulek
()
Ответ на: комментарий от emulek

Мне кажется, что есть некая корреляция между мужичками на собеседованиях и вопросами про мультилайновые регекспы, где сед если и вспоминают, то в последнюю очередь, причём в убеждении, что его надо обязательно обвесить грепом и авком. На SO тоже заметно. Ну не читают люди маны, поэтому свято верят, что sed — это не редактор потока, как, казалось бы, подсказывает само название, а шняжка для однострочников с единственной командой s///

Особенно убивали диалоги типа «Как? Вы не знаете ни Руби ни Питона? На чём вы вообще пишете тогда? — В основном на баше. — Но в баше же нет массивов!»

deterenkelt
()
Ответ на: комментарий от deterenkelt

Выдрать IP(sed) (комментарий)

Для шел-скриптов fork (вызов внешних программ) есть фактор их быстродействия.

Пример: переписал скрипт один к одному с csh на perl — шел-скрипт исполнялся 52мин, а перл-скрипт 1.8сек в тех же условиях

sdio ★★★★★
()
Ответ на: комментарий от sdio

Типа сам себя поцитировал — сразу значимость подлетела? Я за это только галочку на демагог-бинго.жпг могу поставить. Во-первых, синтаксис csh от bash далеко позади, а во-вторых, это не конкретный пример с конкретными данными, на который можно и нужно было бы дать ссылку, а выдержка из чего-то эксперимента, непонятно как проводившегося. Я, знаете ли, тоже могу скрипт на баше написать, так что он на пустом месте тормозить будет. Засунув sleep в trap на DEBUG, например.

deterenkelt
()
Ответ на: комментарий от deterenkelt

Для шел-скриптов fork (вызов внешних программ) есть фактор их быстродействия.

Ты же сам говоришь что пишешь на баш с активным использованием grep/sed/awk. Так вот в том csh было активное их (coreutils) использование. *sh — клей для coreutils и пр. внешних программ.

На баше можно попытаться писать только используя builtin, но это пытка и костыли.

Поэтому чуть сложнее «однострочника» (считай скрипт больше десятка-двух строк) писать на шеле — дурной тон. А кичиться незнанием perl/tcl/... вообще расписаться в профнепригодности.

sdio ★★★★★
()
Ответ на: комментарий от sdio

Мне тоже один любитель perl-а утверждал, что perl - это дружественный человеку shell и прислал для примера один трехстрочник вместо 10 на shell. Результат однако оказался обратным, сожрал гигабайты памяти, проработал несколько часов (запущен был в конце дня), но до результата не дошел. Обычный скрипт отработал за полчаса.

Это не означает, что я против perl, сам изредка пользуюсь, но все в одну бочку ...

io ★★
()
Ответ на: комментарий от io

Не надо передергивать. На всем можно написать плохую программу.

Но разница в 150 раз ставит крест на *sh, если нужно что-то сложнее пары-тройки пайпов в скрипте.


$ time bash -c 'for i in {1..10000}; do /bin/true; done'

real	0m5.261s
user	0m0.260s
sys	0m1.096s

$ time bash -c 'for i in {1..10000}; do true; done'

real	0m0.033s
user	0m0.032s
sys	0m0.004s

sdio ★★★★★
()
Ответ на: комментарий от sdio

Вот, вот, «На всем можно написать плохую программу».

Да perl бывает очарователен дабы что-то быстро набросать и несколько раз использовать, но если важна именно скорость (и не только это), то меня просили реализовать другой вариант.

Если же скорость не очень критична, а чем заняться в параллель найдется всегда, то на чем быстрее набросалось, то и лучше.

Как говориться Фортран программист напишет Фортран программу на любом языке. И зачем его ломать? Хотя, кончено, Java программы от них омерзительны, но хорошо передергивают на подобных for-циклах, пока не ткнешь в реальный пример.

Это я не к тому, конечно, что языков учить не надо ... Давно не попадалось таких проектов, где можно обойтись парой-другой. Но некоторым везет.

io ★★
()
Ответ на: комментарий от sdio

Значит кому-то надо было выбирать другую более консервативную отрасль для работы. А в нашей надо себя заставлять учить что-то каждый день (желательно на практике, кто мешает сказать себе, о я чувствую Питон вполне себе хорош для этой задачи - начну учить хотя бы с нее, у меня это отлично работает).

Вполне могу поверить, что где-то знание Питона супербонус. Это же очередной shell с человеческим лицом. Огромные билдовые системы написаны именно на нем, разнообразные расширения к массе приложений аналогично. Уж как минимум понимать-то точно было бы неплохо.

Хотя, конечно, зацикленность HR на знании специфического применение конкретного языка здесь и сейчас тоже может быть маразм (хотя для краткосрочного критично), точно как и указание возраста в вакансии. Когда первый раз встретил ограничение до 70 лет понял, что системе образования сильно поплохело.

io ★★
()
Ответ на: комментарий от sdio

Так вот в том csh было активное их (coreutils) использование

Одно то, что оно там было, ничего нам не говорит о том, было ли это необходимо и могло или не могло быть быстрее. Ты демагогию будешь разводить или может хотя бы для приличия из пальца те скрипты высосешь?.. :}

deterenkelt
()
Ответ на: комментарий от deterenkelt

Впрочем, давай попробуем разобраться:

Предположим есть лог веб-сервера, пусть поле N1 это IP клиента. В файле 1000000 строк (все IP разные)

Надо все IP клиентов отрезолвить. В тесте предположим, что ДНС отвечает мгновенно, будем вызывать /bin/echo (или /bin/true)

Твое решение?

sdio ★★★★★
()
Последнее исправление: sdio (всего исправлений: 1)
Ответ на: комментарий от sdio

Для одноразового, наколенного решения вполне сойдёт. Переписывать на perl — это уже скрипт на пол-экрана выйдет.

beastie ★★★★★
()
Ответ на: комментарий от beastie

Для одноразового, наколенного решения вполне сойдёт.

Вся суть шел скриптов в этой фразе.

В реале нужно отрезолвить и заменить в логе ip на имена, а не просто выплюнуть их в stdout

sdio ★★★★★
()
Последнее исправление: sdio (всего исправлений: 1)
Ответ на: комментарий от sdio

Тебя вообще-то просили продемонстрировать свои знания bash и perl, ну да ладно. Моё решение было бы аналогично таковому у beastie. А если прям кровь из носа нужна была скорость, то я бы написал на Си, там на один экранчик бы вышло. Прям как на перле.

deterenkelt
()
Ответ на: комментарий от deterenkelt

меня никто не просил демонстрировать знания. а вот искать скрипт десятилетней давности я точно не собираюсь. если ты так и не понял как дорого по времени обходится запуск внешних программ, то я тебе уже ничем помочь не смогу.

то что написал бисти, никому не нужное, в реале придётся с каждым адресом работать отдельно и действий будет значительно больше

ога, работа со строками на С просто сказка

sdio ★★★★★
()
Ответ на: комментарий от sdio

В том то и суть баш. Да и вообще всего остального.

Т.е. если надо надо «быстро (и просто) состряпать» — будет долго исполнятся.

Надо, что бы «бысто исполнялось» — надо много думать и писать.

И то и другое — я не знаю, где такое получить. Классический trade-off.

Всё таки надо различать одноразовые и периодические таски.

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 2)
Ответ на: комментарий от beastie

Ну дык, с чего все началось? Школотун радостно и пафосно заявил, что баш и корутилс достаточно для всего! perl/python/ruby/tcl/... не нужны, а работодатели сплошные идиоты.

sdio ★★★★★
()
Последнее исправление: sdio (всего исправлений: 1)
Ответ на: комментарий от Deleted

cut -d' ' -f1 log_file | sort -u | while read ip; do host $ip; done

Это в ответ на сообщение «миллион запусков host». У тебя их тут меньше будет что-ли?

И если надо в логе заменить IP имена, а не просто отрезолвить? (собственно для этого и предлагалось их резолвить)

name=`host ip | cut -f5`
sed "${LINENUMBER}s/$ip/$name/" -- или соотв. аналог этой команды

Такая шняга будет тормозить только на запусках host, cut, sed

sdio ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.