awkによって検出された各オカレンスを配列に格納します

Aug 20 2020

私の前の質問には「重複」のフラグが付けられ、これとこれが指摘されました。それらのスレッドで提供されるソリューションは、これをまったく解決しません。

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を使用したくありません。

提供されたこのリンクに基づく:

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

どんな助けでも素晴らしいでしょう。

回答

2 PaulHodges Aug 20 2020 at 02:12

チャールズが提案...

ブロックの改行を削除するように編集されました(すべてのレコードではありません)

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]
3 M.NejatAydin Aug 20 2020 at 00:44

プレーンでの実装は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 < fileます。の使用awkは必須ではありませんが、スクリプトはawk出力でも正しく機能します。

ZYXRhythm Aug 20 2020 at 12:43

ポールの答えは私が望むことをするので、私はそれを受け入れられた答えとしてフラグを立てました。彼のソリューションでは、配列に格納されているすべての値の下部に空白の余分な行が生成されますが、これは問題ありませんが、とにかく簡単に削除できるので、気にしませんでした。しかし、私はこの同じ質問を別のサイトにも投稿しました。ポールの答えは良かったのですが、より良い解決策を見つけました。

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

上記は仕事をし、空白の余分な行を生成せず、その1つのライナーです。

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