【问题标题】:Display data between two fixed patterns在两个固定模式之间显示数据
【发布时间】:2018-11-10 21:26:04
【问题描述】:

我有随机数据从源输入到文件中。我必须通读文件并仅提取介于特定模式之间的那部分数据。

示例:假设文件myfile.out 如下所示。

info-data
some more info-data
=================================================================
some-data
some-data
some-data
=================================================================

======================= CONFIG PARMS : ==========================
some-data
some-data
some-data
=================================================================

======================= REQUEST PARAMS : ========================
some-data
some-data
some-data
=================================================================

===================== REQUEST RESULTS ===========================
some-data
=================================================================
some-data
some-data
=================================================================
Data-I-Need
Data-I-Need
...
...
...
Data-I-Need
==========================F I N I S H============================

some-info-data

我正在寻找仅与此特定模式匹配的数据

=================================================================
Data-I-Need
Data-I-Need
...
...
...
Data-I-Need
==========================F I N I S H============================

我确实试着环顾了一下,比如

How to select lines between two marker patterns which may occur multiple times with awk/sed

Bash. How to get multiline text between tags

但是那里给出的awksed 解决方案似乎不起作用,这些命令没有给出任何错误或输出。

我试过了

PATTERN1="================================================================="
PATTERN2="==========================F I N I S H============================"
awk -v PAT1="$PATTERN1" -v PAT2="$PATTERN2" 'flag{ if (/PAT2/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /PAT1/{flag=1}' myfile.out

PATTERN1="================================================================="
PATTERN2="==========================F I N I S H============================"
awk  -v PAT1="$PATTERN1" -v PAT2="$PATTERN2" 'PAT1 {flag=1;next} PAT2 {flag=0} flag { print }' file

也许是因为模式?或者我做错了什么。

脚本将在 RHEL 6.5 上运行。

【问题讨论】:

  • 你需要数据的开始和结束模式吗?
  • @oliv 不,我不需要那个。

标签: shell awk sed


【解决方案1】:

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

sed -r '/^=+$/h;//!H;/^=+F I N I S H=+$/!d;x;s/^[^\n]*\n|\n[^\n]*$//g' file

在保留空间中存储仅包含= 的行(替换之前的任何内容)。附加所有其他行以保留空间。如果当前行不是包含= 后跟F I N I S H 后跟= 的行,请将其删除。否则,交换到保留空间,删除第一行和最后一行并打印剩余部分。

【讨论】:

    【解决方案2】:

    假设您只需要数据而不是模式,使用 GNU awk:

    awk -v RS='\n={26,}[ A-Z]*={28,}\n' 'RT~/F I N I S H/' file
    

    记录分隔符RS 设置为匹配具有一系列= 和中间一些可选大写字符的行。

    唯一的语句是检查记录终止符RT(当前记录)是否包含FINISH关键字。如果是这样,awk 将打印由多行组成的整个记录​​。

    【讨论】:

    • 我意识到,我给出的模式不是仪式......它是F I N I S H而不是FINISH
    • @Marcos 我用新模式更新了答案。 (您可以更改语句RT~/.../ 以匹配任何字符串)
    • @Marcos 什么不完全工作?你确定你使用 GNU awk 吗?
    • 它是 GNU Awk 3.1.7
    【解决方案3】:

    sed 可以处理这个问题。

    假设您想保留页眉和页脚行 -

    $: sed -En '/^=+$/,/^=+F I N I S H=+$/ { /^=+$/ { x; d; }; /^[^=]/ { H; d; }; /^=+F I N I S H=+$/{ H; x; p; q; }; }' infile
    =================================================================
    Data-I-Need
    Data-I-Need
    ...
    ...
    ...
    Data-I-Need
    ==========================F I N I S H============================
    

    如果没有,请使用

    sed -En '/^=+$/,/^=+F I N I S H=+$/ { /^=+$/ { s/.*//g; x; d; }; /^[^=]/ { H; d; }; /^=+F I N I S H=+$/{ x; p; q; }; }' infile
    

    请注意,如果您不使用 GNU sed,则需要插入换行符而不是所有这些分号。

    sed -En '
      /^=+$/,/^=+F I N I S H=+$/ {
        /^=+$/ {
          s/.*//g
          x
          d
        }
        /^[^=]/ {
          H
          d
        }
        /^=+F I N I S H=+$/{
          x
          p
          q
        }
    }' infile
    
    Data-I-Need
    Data-I-Need
    ...
    ...
    ...
    Data-I-Need
    

    打破它-

    sed -En '...'
    

    -En 表示使用扩展模式匹配(-E,我实际上只用于+'s),除非特别要求,否则不输出任何内容(-n)。

    /^=+$/,/^=+F I N I S H=+$/ {...}
    

    说只在所有= 的行和所有= 的行之间执行这些命令,除了中间某处的F I N I S H{} 之间的所有内容都将在它们之间的所有行上进行检查。这确实意味着从 first =+ 行开始,但没关系,我们在里面处理。

    (a) /^=+$/ { x; d; };
    (b) /^=+$/ { s/.*//g; x; d; };
    

    (a) 在每一行都是= 的行上,将当前行(“模式空间”)与“保持空间”交换(x),然后删除(d ) 模式空间。这会保留当前行并删除您在错误启动时可能在上面积累的任何内容。 (请记住 -n 会阻止任何内容打印,直到我们需要它为止。)

    (b) 表示先擦除当前行,然后交换并删除。它仍然添加一个换行符。你想删除它吗?

    /^[^=]/ { H; d; };
    

    两个版本都使用这个。在任何=开头的行上,将其添加到保持空间(H),然后删除模式空间(d)。删除总是重新开始循环,读取下一条记录。

    (a) /^=+F I N I S H=+$/{ H; x; p; q; };
    (b) /^=+F I N I S H=+$/{ x; p; q; };
    

    在所有 = 之间带有标记 F I N I S H 字符串的任何行上,(a) 将首先将 (H) 模式附加到保留空间 - (b) 不会。然后两者将交换模式和保持空间(x),打印(p)模式空间(现在是累积到保持空间中的值),然后删除(d)模式空间,触发下一个循环。

    此时,您将在初始切换之外,因此除非发生所有= 的另一行,否则您将跳过所有剩余的行。如果这样做,它将再次开始累积记录,但不会打印它们,除非它击中另一个 F I N I S H 记录。

    }' infile
    

    这只是关闭脚本并传入您使用的任何文件名。请注意,这不是就地编辑...

    希望对您有所帮助。

    【讨论】:

    • 这对我不起作用,我会尝试对此进行更多测试。
    • 它做了什么?
    【解决方案4】:

    虽然那里已经有sed 解决方案,但我喜欢sed 的简单性:

    sed -n '/^==*\r*$/,/^==*F I N I S H/{H;/^==*[^F=]/h;${g;p}}' file
    

    在这个sed 命令中,我们为要运行的命令设置了一个范围。此范围以一行开始,仅包含并结束于=,然后在以= 开头并指向F I N I S H 的行结束。现在我们的命令:

    H 立即附加每一行以保留空间。然后/^==*[^F=]/h 在其他部分的页眉或页脚上执行,它将保留空间替换为当前模式空间。

    在最后一行,我们将当前模式空间替换为保持空间中的内容,然后使用${g;p} 打印它。整个输出如下:

    =================================================================
    Data-I-Need
    Data-I-Need
    ...
    ...
    ...
    Data-I-Need
    ==========================F I N I S H============================
    

    【讨论】:

    • 我不需要页眉和页脚行。
    • 然后将结果添加到sed '1d;$d;'
    • 由于某种原因您的解决方案没有成功,我将进一步测试以了解原因。
    • 请详细说明。 它不起作用没有描述问题是什么,你是否得到任何结果,如果是,那是什么。不过我支持@potong 的回答。这背后有一个好主意。
    猜你喜欢
    • 2021-10-03
    • 1970-01-01
    • 2013-09-19
    • 1970-01-01
    • 2020-05-25
    • 2023-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多