Stocker chaque occurrence trouvée par awk dans un tableau
Ma question précédente était signalée "en double" et on m'a signalé ceci et cela . Les solutions fournies sur ces threads ne résout pas du tout cela.
Contenu de 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
J'ai besoin d'extraire "PATTERN1" et "PATTERN2" + lignes entre les deux, et la commande suivante le fait parfaitement:
awk '/ PATTERN1 /, / PATTERN2 /' ./file.txt
Production:
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
Mais maintenant, j'essaye de créer un script bash qui:
- utilise awk pour trouver les lignes entre PATTERN1 et PATTERN2
- stocker chaque occurrence de PATTERN1 + lignes entre + PATTERN2 dans un tableau
- fait 1 & 2 jusqu'à la fin du fichier.
Clarifier. Signifie stocker les lignes suivantes à l'intérieur des guillemets:
"PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2"
à array[0]
et stockez les lignes suivantes à l'intérieur des guillemets:
"PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2"
à array[1]
et ainsi de suite ..... s'il y a plus d'occurrence de PATTERN1 et PATTERN2
Ce que j'ai actuellement:
#!/bin/bash
var0=`cat ./file.txt`
mapfile -t thearray < <(echo "$var0" | awk '/PATTERN1 /,/PATTERN2/')
Ce qui précède ne fonctionne pas.
Et autant que possible, je ne veux pas utiliser mapfile, car le script pourrait être exécuté sur un système qui ne le prend pas en charge.
Sur la base de ce lien fourni:
myvar=$(cat ./file.txt)
myarray=($(echo "$var0" | awk '/PATTERN1 /,/PATTERN2/'))
Mais quand je fais echo ${myarray[1]}
Je reçois une réponse vide.
Et quand je fais echo ${myarray[0]}
Je reçois:
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
Ce à quoi j'attends quand je fais écho ${myarray[0]}
PATTERN1 Some line of text 3 Some line of text 4 Some line of text 5 PATTERN2
Ce à quoi j'attends quand je fais echo ${myarray[1]}
PATTERN1 Some line of text 9 Some line of text 10 Some line of text 11 PATTERN2
Toute aide sera appréciée.
Réponses
Comme Charles l'a suggéré ...
Édité pour supprimer la nouvelle ligne du et du bloc (pas tous les enregistrements)
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)
Je l'ai reformaté. Il devenait un peu chargé et difficile à lire.
Et pour le tester -
$: echo "[${array[1]}]"
[PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2]
En passant, il me semble très étrange d'inclure les valeurs sentinelles redondantes dans les éléments de données, donc si vous voulez les supprimer:
$: 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]
Une implémentation en clair bash
pourrait être quelque chose comme ça:
#!/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
Exécutez comme ./script < file
. L'utilisation de awk
n'est pas requise, mais le script fonctionnera également correctement sur la awk
sortie.
La réponse de Paul fait ce que je veux, alors je l'ai signalée comme étant la réponse acceptée. Bien que sa solution produise une ligne supplémentaire vide au bas de chaque valeur stockée dans le tableau, ce qui est correct, il est facile de la supprimer de toute façon, donc cela ne me dérangeait pas. Mais j'ai aussi posté cette même question sur un autre site, et bien que la réponse de Paul soit bonne, j'ai trouvé une meilleure solution:
IFS=$'\r' read -d'\r' -a ARR < <(awk '/PATTERN1/,/PATTERN2/ {if($0 ~ /PATTERN2/) printf $0"\r"; else print}' file.txt)
Ce qui précède fait le travail, ne produit pas de ligne supplémentaire vierge et c'est une ligne unique.
echo "${ARR[1]}"
echo "${ARR[0]}"
Production:
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