通过匹配(包括)变量中第一个字母后的字符串,从字符串中分离产品名称

时间:2018-07-05 13:57:49

标签: string bash letter

我在文本文件中有一堆以下模式的字符串:

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个可能的设备/设备名称编写测试,然后在减去的测试之后附加设备名称。然后测试与设备/设备(或其他名称)实际匹配的变量,然后使用该变量输入数据库。

是否可以在文本文件中编写一行内容来选择所有内容,包括一行中的第一个字母?然后我减去AB i之后的所有内容以获取注释,而AB i之前的所有内容都将成为设备名称。

3 个答案:

答案 0 :(得分:1)

删除$ {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/')

我也忘记了文本行周围的双引号。

答案 1 :(得分:1)

您可以使用sedread来更好地控制解析。

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

基本上,读取允许您在一行中分配多个变量。 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,以防止它转储该行)不匹配。)

答案 2 :(得分:1)

您的问题尚不清楚,但似乎您可能正在尝试将字符串解析为子字符串。使用GNU awk尝试此操作以使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

适合的按摩...