Изолируйте названия продуктов от строк, сопоставляя строку после (включая) первую букву в переменной - PullRequest
0 голосов
/ 05 июля 2018

У меня есть куча строк следующего шаблона в текстовом файле:

201194_2012110634 Appliance 130 AB i Some optional (Notes )
300723_2017050006(2016111550) Device 16 AB i Note

Первая часть является серийной, вторая - датой. Имя и модель устройства / устройства (около 10 возможных различных имен) - это строка после номера даты и до (включая AB i).

Мне удалось выделить даты и сериалы, используя

SERIAL=${line:0:6}
YEAR=${line:7:4}

Я пытаюсь изолировать имя устройства и записку после этого:

#!/bin/bash
while IFS= read line || [[ -n $line ]]; do
  NAME=${line#*[a-zA-Z]}
  STRINGAP='Appliance '"${line/#*Appliance/}"

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

NAME = ppliance 130 AB i Some optional (Notes )

Второй подход - написать тесты для каждого из ~ 10 возможных имен устройств / устройств, а затем добавить имя устройства после вычитаемого теста. Затем проверьте переменную, которая фактически соответствует Appliance / Device (или другому имени), и используйте ее для ввода в базу данных.

Можно ли написать в текстовом файле строку, которая бы выделяла все, включая первую букву в строке? Затем я вычел бы все после AB i, чтобы получить заметки, и все, прежде чем AB i станет именем устройства.

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Вы можете использовать sed и read, чтобы дать вам больше контроля над синтаксическим анализом.

tmp> line2="300723_2017050006(2016111550) Device 16 AB i Note"
tmp> read serial date type val <<<$(echo $line2 | \
         sed 's/\([0-9]*\)_\([0-9]*\)[^A-Z]*\(Device\|Appliance\) \
         \([0-9]*\).*/\1 \2 \3 \4/')
tmp> echo "$serial|$date|$type|$val"
300723|2017050006|Device|16

По сути, read позволяет назначать несколько переменных в одной строке. Параметр sed анализирует строку и выдает ее результаты с разделителями-пробелами. Вы также можете прочитать каждую переменную отдельно, если вы не против запустить sed несколько раз:

 device="$(echo $line2 | sed -e 's/^.*Device \([0-9]*\).*/\1/;t;d')"
 appliance="$(echo $line2 | sed -e 's/^.*Appliance \([0-9]*\).*/\1/;t;d')"

Таким образом, $device заполняется устройством, если оно присутствует, и в противном случае остается пустым (обратите внимание на -e и ;t;d в конце регулярного выражения, чтобы оно не сбрасывало строку, если оно не соответствует).

0 голосов
/ 05 июля 2018

Ваш вопрос не ясен, но, похоже, вы пытаетесь разобрать строки в подстроки. Попробуйте это с GNU awk для 3-го аргумента для match () и дайте нам знать, если вы ищете что-то еще:

$ awk 'match($0,/^([0-9]+)_([0-9]+)(\([0-9]+\))?\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)/,a) {
    for (i=1; i<=8; i++) {
        print i, a[i]
    }
    print "---"
}' file
1 201194
2 2012110634
3
4 Appliance
5 130
6 AB
7 i
8 Some optional (Notes )
---
1 300723
2 2017050006
3 (2016111550)
4 Device
5 16
6 AB
7 i
8 Note
---

Если вы хотите, например, вывод CSV, то это будет просто:

$ awk -v OFS=',' 'match($0,/^([0-9]+)_([0-9]+)(\([0-9]+\))?\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)/,a) {
    for (i=1; i<=8; i++) {
        printf "%s%s", a[i], (i<8?OFS:ORS)
    }
}' file
201194,2012110634,,Appliance,130,AB,i,Some optional (Notes )
300723,2017050006,(2016111550),Device,16,AB,i,Note

Массаж для костюма ...

0 голосов
/ 05 июля 2018

Удалите строку $ {line # * [az-A-Z]} (которая, как вы видите, удалит первый символ имени), и вместо этого используйте

STRINGAP=$(echo "$line" | sed 's/^[0-9_]* \(.*\) AB i.*/\1/')

Это отбрасывает первые цифры и подчеркивание, и все, начиная от "AB i" и заканчивая.

Редактировать: Детали неясны - хотите ли вы сохранить "AB i", и всегда ли это будет "AB i"? Если вы хотите, измените строку на

STRINGAP=$(echo "$line" | sed 's/^[0-9_]* \(.* AB i\).*/\1/')

Я также забыл двойные кавычки вокруг строки текста.

...