Разбор файла скриптом bash - PullRequest
3 голосов
/ 12 октября 2019

У меня есть файл с несколькими строками, который структурирован, как показано ниже

MSH|^~\&|Xatidok|V10.0.2.000|OSestra|x-tention|201203060855||ADT^A03|2914|P|2.3^AA&BB
EVN|A03|201203060855|201203060855|01|Fidani
PID|||00019380|2012049008^120005548^302830|PATIDOK-person^InRid^|Rudi|19111111|F|||Rose |A|Pens.
NK1||IRergrun^RROSlf^||Rose ^^Wels^^4600^A|07242123123|||||||||||||||||||||||||||||||
PV1||I|1212^G442^G442-||0|||||||||||2012049008|General|||||||||||||||||||12|||||201202060927|||||||

Таким образом, в основном есть строки с данными, разделенными с помощью каналов (|), и я хочу проанализировать их, написав bashscript.

Итак, вкратце это структура

  • Сегмент> строки
  • Поле> ячейки между |field |
  • Компонент> каждое поле имеет (или не имеет) несколько полей, разделенных ^
  • Подкомпонент> разделенных &

Идея запускаСценарий: ./script.sh filename command

команда должна выглядеть следующим образом: MSH.2.3.4 или короче

Значение: получить доступ к полю, которое начинаетсяс MSH, поле № 2, компонент № 3, подкомпонент 4

Итак, моя логика синтаксического анализа заключается в следующем: я хочу создать массив, который будет хранить каждую строку (сегмент) из файла следующим образом:

#!/bin/bash

file_to_be_parsed=$1
command=$2
counter=0

#read the file and split it into lines (segments) by creating an array called segments which holds all the lines (segment) in it
#array segments[] holds every line/segment of the file indexed from 0 to X

while IFS= read -a segment; do
     segments[$counter]=$segment
     counter=$((counter+1)); 
done < $file_to_be_parsed

ВТОРОЙ: Мой второй шаг - разделить каждый элемент массива еще на один шаг в зависимости от разделителя, и я могу сделать это следующим образом:

IFS="|" read -r field <<< (here i can't figure out)

, но на самом деле я не могусоздать 2D-массив в Bash, хотя я много искал. Тогда я смогу получить доступ к определенным полям ...

Так может кто-нибудь помочь мне, как разделить эти элементы массива на поля ...

Ответы [ 2 ]

4 голосов
/ 12 октября 2019

Это классическая awk (стандартная Linux gawk) проблема.

Вот простой скрипт, который проверяет входные аргументы и анализирует только обязательные поля, компонент и подкомпонент, используя внутренние * awk split функция.

Пользователю рекомендуется упростить макеты вывода скрипта.

Что касается аргументов скрипта, все они обязательны (некоторые могут игнорироваться), файл input.txt должен быть последним.

input.txt

MSH|^~\&|Xatidok|V10.0.2.000|OSestra|x-tention|201203060855||ADT^A03|2914|P|2.3^AA&BB
EVN|A03|201203060855|201203060855|01|Fidani
PID|||00019380|2012049008^120005548^302830|PATIDOK-person^InRid^|Rudi|19111111|F|||Rose |A|Pens.
NK1||IRergrun^RROSlf^||Rose ^^Wels^^4600^A|07242123123|||||||||||||||||||||||||||||||
PV1||I|1212^G442^G442-||0|||||||||||2012049008|General|||||||||||||||||||12|||||201202060927|||||||

script.awk

BEGIN {FS="|"; componentSeperator="^"; subComponentSeperator="&"}
function readArgs() {
     if (passedReadArgs == 1) return;
     if (length(field) == 0) {print "Missing field string argument, exiting."; exit;}
     if (length(fieldNumber) == 0) {print "Missing fieldNumber number argument, exiting."; exit;}
     if (length(componentNumber) == 0) {print "Missing componentNumber number argument, exiting."; exit;}
     if (length(subComponentNumber) == 0) {print "Missing subComponentNumber number argument, exiting."; exit;}
     passedReadArgs = 1;
}
{
     readArgs();
     if ($0 !~ field) next;

     print "Arguments: "field, fieldNumber, componentNumber, subComponentNumber;

     print "field["fieldNumber"] = "$fieldNumber;

     split($fieldNumber, componentsArr, componentSeperator);
     if (length(componentsArr[componentNumber]) > 0) {
          print "component["componentNumber"] = "componentsArr[componentNumber];
          split(componentsArr[componentNumber], subComponentsArr, subComponentSeperator);
          if (length(subComponentsArr[subComponentNumber]) > 0) print "subComponent["subComponentNumber"] = "subComponentsArr[subComponentNumber];
     }
}

, выполняющий сценарий script.awk:

awk -f script.awk field="MSH" fieldNumber=11 componentNumber=2 subComponentNumber=2 input.txt

вывод:

Arguments: MSH 12 2 2
field[12] = 2.3^AA&BB
component[2] = AA&BB
subComponent[2] = BB

Arguments: NK1 5 3 2
field[5] = Rose ^^Wels^^4600^A
component[3] = Wels


Arguments: PID 7 3 2
field[7] = Rudi
2 голосов
/ 12 октября 2019

Fr пуэр решение только для bash, может использовать массивы bash для разделения строки на поля, компоненты, подкомпоненты. При условии, что вам не нужно запускать код для больших наборов данных, все должно быть в порядке.

Рассматривает переход на более мощный движок (awk, python, perl) для больших проблем.

#! /bin/bash
file=$1
command=$2
   # Split command into key, so that items are key[0], key[1], ...
IFS="." read -a k <<<"$command"

  # Look for matching line to k[0]
while IFS='|' read -a fa ; do
  # Skip to next row if no match.
  [ "${fa[0]}" = "${k[0]}" ] || continue ;
  # Field
  v=${fa[${k[1]}-1]}
  # Component
  if [ "${#k[@]}" -gt 2 ] ; then
      IFS="^" read -a fb <<<"$v"
      v=${fb[${k[2]}-1]}
  fi
  # Sub component
  if [ "${#k[@]}" -gt 3 ] ; then
      IFS="&" read -a fc <<<"$v"
      v=${fc[${k[3]}-1]}
  fi
  echo "V=$v" ;
  break
done <"$file"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...