【问题标题】:Store each occurence found by awk to an array将 awk 找到的每个事件存储到一个数组中
【发布时间】:2020-12-08 23:38:46
【问题描述】:

我之前的问题被标记为“重复”,我被指向thisthis。这些线程上提供的解决方案根本无法解决这个问题。

file.txt 的内容:

Some line of text 0
Some line of text 1
Some line of text 2
PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2
Some line of text 6
Some line of text 7
Some line of text 8
PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2
Some line of text 12
Some line of text 13
Some line of text 14

我需要在两者之间提取“PATTERN1”和“PATTERN2”+行,下面的命令可以完美地做到这一点:

awk '/PATTERN1 /,/PATTERN2/' ./file.txt

输出:

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

但现在我正在尝试创建一个 bash 脚本:

  1. 使用 awk 查找 PATTERN1 和 PATTERN2 之间的线
  2. 将每次出现的 PATTERN1 + 行之间的 + PATTERN2 存储在 一个数组
  3. 执行 1 和 2 直到文件结束。

澄清一下。表示将以下行存储在引号内:

"PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2"

array[0]

并将以下行存储在引号内:

"PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2"

array[1]

等等.....如果PATTERN1和PATTERN2的出现次数更多

我目前拥有的:

#!/bin/bash
var0=`cat ./file.txt`
mapfile -t thearray < <(echo "$var0" | awk '/PATTERN1 /,/PATTERN2/')

上述方法不起作用。
并且我尽可能不想使用 mapfile,因为该脚本可能在不支持它的系统上执行。

基于this提供的链接:

myvar=$(cat ./file.txt)
myarray=($(echo "$var0" | awk '/PATTERN1 /,/PATTERN2/')) 

但是当我这样做时echo ${myarray[1]}

我得到一个空白回复。

当我这样做时echo ${myarray[0]}

我明白了:

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

当我回显${myarray[0]}时我期望什么

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

当我做echo ${myarray[1]}时我期望什么

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

任何帮助都会很棒。

【问题讨论】:

  • 让您的 awk 在每个段之后插入一个文字 NUL,然后您可以使用 readarray -d '' arrayname &lt; &lt;(awk ...) 填充由这些 NUL 分段的数组。

标签: arrays bash shell awk


【解决方案1】:

bash 的实现可能是这样的:

#!/bin/bash

beginpat='PATTERN1'
endpat='PATTERN2'

array=()
n=-1
inpatterns=
while read -r; do
    if [[ ! $inpatterns && $REPLY = $beginpat ]]; then
        array[++n]=$REPLY
        inpatterns=1
    elif [[ $inpatterns ]]; then
        array[n]+=$'\n'$REPLY
        if [[ $REPLY = $endpat ]]; then
            inpatterns=
        fi
    fi
done

# Report captured lines
for ((i = 0; i <= n; ++i)); do
    printf "=== array[%d] ===\n%s\n\n" $i "${array[i]}"
done

./script &lt; file 运行。不需要使用 awk,但脚本也可以在 awk 输出上正常工作。

【讨论】:

  • "但现在我正在尝试创建一个 bash 脚本: 1. 使用 awk" ...除非那是 XY Problem
  • @PaulHodges 该脚本也适用于 awk 输出。
【解决方案2】:

正如 Charles 建议的那样......

编辑以从 block 的 and 中去除换行符(不是每条记录)

while IFS= read -r -d '' x; do array+=("$x"); done < <(awk '
  /PATTERN1/,/PATTERN2/ { if ( $0 ~ "PATTERN2" ) { x=$0; printf "%s%c",x,0; next }
                          print }' ./file.txt)

我重新格式化了它。它变得有点忙,难以阅读。

并对其进行测试 -

$: echo "[${array[1]}]"
[PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2]

顺便说一句,在数据元素中包含冗余的标记值对我来说似乎很奇怪,所以如果你想去掉这些:

$: while IFS= read -r -d '' x; do array+=("$x"); done < <(
    awk '/PATTERN1/,/PATTERN2/{ if ( $0 ~ "PATTERN1" ) { next }
      if ( $0 ~ "PATTERN2" ) { len--; 
        for (l in ary) { printf "%s%c", ary[l], l<len ? "\n" : 0; } 
        delete ary; len=0; next }
      ary[len++]=$0;
    }' ./file.txt )

$: echo "[${array[1]}]"
[Some line of text 9
Some line of text 10
Some line of text 11]

【讨论】:

  • @PaulHodges 哇。哇。现在只需要 3 行就可以解决我 2 天的问题。这非常有效。你让我的一天变得非常非常好。太感谢了! =)
  • 谢谢,埃德。你们俩都是我心目中的神,我让你感到困惑。仍然希望在这些日子里开车带你们俩去吃午饭,哈哈……对不起,查尔斯。和往常一样,你是对的。
  • 我被限制在没有敏感信息的情况下发布实际数据或至少实际行。为什么。所以我创建了 file.txt 作为虚拟对象。但是 PATTERN1 和 PATTERN2 也是必不可少的部分,所以应该保留它们。所需的数据块总是以这些模式开始和结束。顺便说一句,再次感谢。
【解决方案3】:

Paul 的答案符合我的要求,因此我将其标记为已接受的答案。尽管他的解决方案在数组中每个存储值的底部产生了一个空白的额外行,这没关系,无论如何它很容易删除,所以我不介意。但我也在另一个网站上发布了同样的问题,虽然 Paul 的回答很好,但我找到了更好的解决方案:

IFS=$'\r' read -d'\r' -a  ARR < <(awk '/PATTERN1/,/PATTERN2/ {if($0 ~ /PATTERN2/) printf $0"\r"; else print}' file.txt)

上面的工作,不会产生一个空白的额外行,它是一个单行。

echo "${ARR[1]}"
echo "${ARR[0]}"

输出:

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

【讨论】:

  • 哈哈!我在测试时使用了回车,但将其切换为 NUL 字节(“正如查尔斯建议的那样”,哈哈),因为如果在记事本等中编辑它,您最终可能会在文件中使用 CRLF。XD
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
相关资源
最近更新 更多