LINUX.ORG.RU
ФорумAdmin

Распарсить две группы файлов и склеить в один

 , ,


0

2

Привет. Есть группа конфигов, порядка 500 файлов. Все файлы имеют одинаковую структуру вида:

[config_name_var]
param1=data1 <some data>
param2=data2
param3="data3" <some data>
param4=data4
param5=data5/data6

(1) Надо вытянуть данные, которые лежат в param3 каждого конфига

(2) вытянуть данные, которые лежат в param4 (получить data4)

(3) объединить полученные данные в одном файле, в виде param3:param4, одна строка=один распарсенный файл (в итоге должно получиться около 500 строк, по количеству конфигов).

---

(1) решаю через sed, просто получая содержимое кавычек

grep "param3" "$file" | sed -e 's/.*"\(.*\)".*/\1/'
Но как натравить sed на множество файлов? Пробовал запихнуть в for, одновременно записывая результат во внешний файл:
for file in $(ls -l /dir/ | grep ^-)
do echo $(grep "param3" "$file" | sed -e 's/.*"\(.*\)".*/\1/') > param3data
done
Но, видимо, что-то пошло не так. Что именно, ткните?

(2) Думаю отлавливать data4 тем же седом, после знака равно - никаких кавычек там нет, но нужна помощь по циклу

(3) paste



Последнее исправление: mammuthus (всего исправлений: 3)

Но, видимо, что-то пошло не так. Что именно, ткните?

Вот: «решаю через sed».

Zmicier ★★★★★
()
cat f1
param1=1x1
param2=1x2
param3=1x3
param4=1x4
cat f2
param1=2x1
param2=2x2
param3=2x3
param4=2x4
for i in f*; do cat "$i" | grep param[3,4] | awk -F"=" '{print $2}' | awk 'BEGIN {FS="\n"; RS=""} {print $1,":",$2}' >> final; done
cat final 
1x3 : 1x4
2x3 : 2x4

Может быть немного сложно вышло, но по другому не надумал...

Niroday
()

А чтобы убрать побелы вокруг ":" надо добавить OFS=«»

{FS="\n"; RS=""; OFS=""}

Niroday
()

Или вообще проще

for i in f*; do cat "$i" | grep param[3,4] | awk -F"=" '{print $2}' | awk 'BEGIN {FS="\n"; RS=""; OFS=":"} {print $1,$2}' >> final; done

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

Ага, осталось от проверки файлов по отдельности. Конечно нужно убрать.

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

Не уверен, но вроде без итерации выдаст только один результат

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

можно проще:

... когда файлов мало, а когда много — уже нельзя, в отличие от
for i in f*; do ...; done

А поскольку доподлинно неизвестно, мало или много, то нельзя, но если очень хочется...

bormant ★★★★★
()

Это же задача для awk!

BEGIN {
  FS="="
  OFS=":"
}

FNR==1&&NF!=1 { #в начале каждого файла, кроме первого
  print param3, param4 # выдаём результат
}

FNR==1 { #в начале каждого файла сбрасываем
  param3=""
  param4=""
}

$1=="param3" { param3=$2; }
$1=="param4" { param4=$2; }

END {
  print param3, param4
}

Запускать так:

awk -f parse.awk все твои файлы

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

Ничего подобного

Вы хотели сказать, что при
cat f* ...
не сработает глобинг и команда cat в свои параметры получит именно один параметр «f*» вместо пачки имен, попавших под указанную маску, а превышение предельного размера (то самое «много файлов») НЕ будет сопровождаться ошибкой «Argument list too long»?

Если да, то нет :-)

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

С учётом https://www.gnu.org/software/gawk/manual/html_node/BEGINFILE_002fENDFILE.html можно упростить:

BEGIN {
  FS="="
  OFS=":"
}

BEGINFILE { #в начале каждого файла сбрасываем
  param3=""
  param4=""
}

$1=="param3" { param3=$2; } # эти части придётся переписать, если значения полей содержат "=". Это несложно - удаляем $1 и используем $0 вместо $2
$1=="param4" { param4=$2; } 

ENDFILE {
  print param3, param4
}
anonymous
()
Ответ на: комментарий от legolegs

Почему вы думаете, что на for это ограничение не распространяется?

В zsh распространяется, ему нужно setopt nullglob или саму маску квалифицировать *(N). Но кто ж в здравом уме для zsh скриптует?

В bash не распространяется.
Про остальные *sh — оставим в качестве домашнего задания...

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

Я не про пустой glob, а про «Argument list too long».

Я тоже. Можете проделать в bash эксперимент:
1) создать в каталоге множество файлов с длинными именами,
2) получить по ls * заветное «Argument list too long»,
3) проверить for f in *; do echo $f; done,
4) погрузить zsh и попытаться выполнить (4), получить «Argument list too long».

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

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

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