【问题标题】:Extracting multi line text from a file between delimiters in bash [duplicate]从bash中分隔符之间的文件中提取多行文本[重复]
【发布时间】:2021-05-02 13:21:53
【问题描述】:

我正在尝试从文本文件中提取多行文本,其中值由分隔符分隔,并将其保存到字符串或数组中。大多数值都是通过 awk 提取并保存到变量中的,但是当我需要将特定产品的多行描述提取到变量/数组中时,就会出现问题。

简化的输入文件语法如下所示: ID;Name;value1;value2;DESCRIPTION;valueX;valueY;

我正在使用awk -F ";" '{print $1}' 提取第一个值,并将它们分配给未来操作的变量,它工作正常,但问题出现在“DESCRIPTION”部分,因为它带有 HTML 标记的多行。描述的外观示例:

value2;"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>


<strong>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</strong>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. </p>

<p style=""text-align: center;"">
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>";valueX;valueY

您能否建议一种方法来完成这项工作,以便我可以将DESCRIPTION分配给bash脚本中的某种变量或数组并进一步操作它?

【问题讨论】:

  • bash 无法解析 HTML 等标记语言的复杂结构
  • 当分隔符是说明的一部分时,您期望将记录与字段分开的条款是什么?具体来说,请注意您的示例描述中的""text-align: center;""&gt; 包含您的分隔符;
  • 它可以是任何其他可以在脚本中实现的东西,perl 或 python。至于第二点,这也是问题的一部分,因为正如您所注意到的,“;”有时包含在 HTML 标记中。作为最后的手段,我可​​以在阅读多行描述文本之前删除所有标签。如果没有其他选项,我们可以假设文本中没有 HTML 标签。但显然我只会删除断线并将其视​​为带有 AWK 的单列。但是再一次我会错过所有的布局。
  • 看起来像一个 csv 文件,因为引用了多行字段,并且该字段中的引号通过加倍转义(例如,"a""b" 表示内容为 a"b 的字段。)因此,问题是关于提取来自 csv 文件的字段,应在此处回答:Bash: Parse CSV with quotes, commas and newlines。或者,考虑安装一个专门的工具,如csvcut 甚至mlr
  • 没错,它是一个csv文件。感谢您指出上述方向。我会调查的

标签: linux bash text split text-extraction


【解决方案1】:

您(最初)要求提供基于awk 的解决方案。正如其他人在 cmets 中提到的那样,有更好的工具来完成这项工作。也就是说,基于4.9 Multiple-Line Records4.7 Defining Fields by Content,您可以尝试以下操作:

$ awk --version
GNU Awk 4.1.4, API: 1.1 (GNU MPFR 4.0.1, GNU MP 6.1.2)
[...]
$ awk 'BEGIN {RS = ";\n"; FPAT = "([^;]+)|(\"<p.+p>\")" } { print "NF = ", NF; for (i = 1; i <= NF; i++) { printf("$%d = %s\n", i, $i) } }' testfile
  1. RS = ";\n" 在这里假设您的输入文件有多个 ID;Name;value1;value2;DESCRIPTION;valueX;valueY; 记录,并且这些记录用 ; 分隔(这是您的示例中 valueY 之后的 ;),后跟 newline
  2. FPAT = "([^;]+)|(\"&lt;p.+p&gt;\")" 是告诉(g)awk 记录字段的样子的“尽力而为”的方法。您可能需要根据需要对其进行修改。实际上说的是有两种字段格式(参见(...)|(...))。第一种字段格式捕获不包含; 的字符串,用于捕获除DESCRIPTION 之外的所有字段。第二种字段格式捕获以"&lt; 开头并以&gt;" 结尾的字符串。

针对一个有2个ID;Name;value1;value2;DESCRIPTION;valueX;valueY;的文件:

$ cat testfile 
ID;Name;value1;value2;"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>


<strong>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</strong>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. </p>

<p style=""text-align: center;"">
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>";valueX;valueY;
ID;Name;value1;value2;"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
  

<strong>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</strong>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. </p>

<p style=""text-align: center;"">
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>";valueX;valueY;

$ awk 'BEGIN {RS = ";\n"; FPAT = "([^;]+)|(\"<p.+p>\")" } { print "NF = ", NF; for (i = 1; i <= NF; i++) { printf("$%d = %s\n", i, $i) } }' testfile
NF =  7
$1 = ID
$2 = Name
$3 = value1
$4 = value2
$5 = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>


<strong>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</strong>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. </p>

<p style=""text-align: center;"">
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>"
$6 = valueX
$7 = valueY
NF =  7
$1 = ID
$2 = Name
$3 = value1
$4 = value2
$5 = "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
  

<strong>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</strong>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. </p>

<p style=""text-align: center;"">
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>"
$6 = valueX
$7 = valueY

【讨论】:

  • 感谢您的努力!该解决方案确实提供了预期的输出
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-03
  • 2016-03-30
  • 2020-03-28
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
相关资源
最近更新 更多