【问题标题】:Print line after multiline match with sed与 sed 多行匹配后打印行
【发布时间】:2013-06-07 01:34:25
【问题描述】:

我正在尝试创建一个脚本来从文件中提取帐户代码。该文件本身很长并且包含很多其他数据,但我在下面包含了我正在查看的部分的摘录(在此摘录之前和之后还有其他内容)

我感兴趣的文件部分有时看起来像这样

  Account       Customer Order No.          Whse         Payment Terms          Stock No.          Original Invoice No.
                                                                                                       VIN No.
 AAAAAA01             9999                  1000             30 days

有时看起来像这样

  Account       Customer Order No.          Whse         Payment Terms          Stock No.          Original Invoice No.
 AAAAAA01             9999                  1000             30 days

(一个字段切断了末端,该字段一直在它自己的行上)

我知道我可以使用| tr -s ' ' | cut -d ' ' -F 1 拉取代码,一旦我有它所在的行,但这不是一个设定的行号(本节之前的内容是动态的)。

我首先尝试处理带有额外字段的案例,我认为与? 进行可选匹配会很容易

用于分隔字段的空格数可以更改,因为这本质上是 OCRed。

到目前为止我的一些尝试 - (假设文件来自 STDIN)

| sed -n '/\s*Account\s\+Customer Order No\.\s\+Whse\s\+Payment Terms\s\+Stock No\.\s\+Original Invoice No\.\s\+VIN No\.\s*/{n;p;}'
| sed -n '/\s*Account\s\+Customer Order No\.\s\+Whse\s\+Payment Terms\s\+Stock No\.\s\+Original Invoice No\.\s*\n\s*VIN No\.\s*/{n;p;}'
| sed -n '/\s*Account\s\+Customer Order No\.\s\+Whse\s\+Payment Terms\s\+Stock No\.\s\+Original Invoice No\.\s*\r\s*VIN No\.\s*/{n;p;}'
| sed -n '/\s*Account\s\+Customer Order No\.\s\+Whse\s\+Payment Terms\s\+Stock No\.\s\+Original Invoice No\.\s*\r\n\s*VIN No\.\s*/{n;p;}'

这些都不匹配

| sed -n '/\s*Account\s\+Customer Order No\.\s\+Whse\s\+Payment Terms\s\+Stock No\.\s\+Original Invoice No\.\s*/,/\s\*VIN No\.\s*/{n;p;}'

这至少匹配了一些东西,但令人沮丧地打印了 VIN 号行,然后每隔一行打印一次。似乎也更难将其标记为表达式的可选部分。

因此,给定完整文件的输入(包括上述任一摘录),我正在寻找任一的输出

AAAAAA01             9999                  1000             30 days

(然后我可以将其修剪为所需的数据)或AAAAAA01,如果有更简单的方法可以直接获取。

【问题讨论】:

  • 你想要得到的输出是什么?从您的所有尝试中都不清楚。
  • 一定要用sed吗? awk 会容易得多。
  • 预期输出是 "AAAAAA01 9999 1000 30 days" 行 - 输入是否包括额外的行和 VIN No. 部分
  • 对于亲密的选民 - 愿意评论为什么?这个问题是重复的吗(我很想看到它重复的问题,它可能正是我需要的!)?它的质量是否低(如果我可以做些什么来提高它的质量,并因此增加它得到答案的可能性,这符合我的最大利益)?是不是跑题了?在我看来,如果您投票结束但对改进问题不感兴趣,那么您就没有使用该系统来实现它的目的。
  • @Barmar 我对工具并不刻意,sed 正是我迄今为止用于类似任务的工具

标签: regex sed multiline


【解决方案1】:

这可能对你有用(GNU sed):

sed -n '/Account/{n;/VIN No\./n;p}' file

sed-n 开关一起使用,这使得sed 的行为类似于grep,即仅使用命令P 或(本例)p 显式打印行。

  • /Account/ 匹配一行与模式Account
  • 仅适用于上述匹配:
  • n 通常这会打印当前行,然后将下一行读入模式空间,但由于-n 正在运行,因此不会进行打印。所以现在模式空间包含下一行。
  • /VIN No\./n 如果当前行包含Vin No,则有效清空模式空间并读入下一行。
  • p 打印当前在模式空间中的任何内容。

所以这是一个条件中的一个条件。当我们遇到Action 时,打印以下行或之后的行。

【讨论】:

  • 嗨@potong,你能解释一下那个脚本到底是做什么的吗?看起来它可能会起作用,但如果我能明白为什么我明天不会回到这里回答同样的问题:p。
  • @ChrisO'Kelly 我认为这基本上是sed 相当于我的awk 答案。您觉得更容易理解的选择。
  • @Barmar 我觉得你的更容易理解,你知道的两者之间的效率有明显差异吗?
【解决方案2】:
awk '/^\s*Account\s\+Customer Order No\.\s\+Whse\s\+Payment Terms\s\+Stock No\.\s\+Original Invoice No\.$/ { 
    getline;
    if (/^\s*VIN No\.$/) getline;
    print;
    exit;
}'

【讨论】:

  • 这比我在sed 看到的任何东西都更具可读性!我一眼就能理解它在做什么。把它交给一天结束,但这可能是我接受的答案。谢谢!
【解决方案3】:

严格遵守您的输入,在这两种情况下,所需的字段都在最后一行。所以要打印最后一行的第一个字段,

awk 'END {print $1}'

结果

AAAAAA01

【讨论】:

  • 嗨,很抱歉,在我最初的问题中,我发布的数据只是文件的一部分并不够清楚(试图让问题保持简短并专注于问题本身)。编辑问题以使其更清楚
猜你喜欢
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
  • 2016-08-15
  • 2017-07-19
相关资源
最近更新 更多