staging.inyokaproject.org

AWK exaktes pattern matching mit Variable

Status: Gelöst | Ubuntu-Version: Ubuntu 20.10 (Groovy Gorilla)
Antworten |

joma1234

Anmeldungsdatum:
2. Juli 2019

Beiträge: Zähle...

Hallo,

ich benutze folgendes Kommando: awk '/M3.S.18/,/end/' bla > bla1

Leider gibt es mir auch Abschnitte aus die mit M3.S.18.6 "anfangen". Daraufhin hab ich herrausgefunden dass ich ein $ einfügen muss, damit es das Zeilenende angibt.

Nun ist es aber so, dass ich anstelle M3.S.18 eine Variable habe und dort funktioniert das nachgestellte $ nicht mehr. awk "/\$rule/,/end/" bla > bla1

Wie könnte ich das gleiche Ergebnis erreichen?

ChickenLipsRfun2eat Team-Icon

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12067

Wieso funktioniert das nicht mehr? Schreibe doch mal deine konkrete Zeile hin.

Ansonsten könntest du mal „.*“ versuchen, das ist ähnlich und erlaubt eine beliebige Anzahl irgendwelcher Zeichen, außer dem Zeilenumbruch.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Bitte mal den tatsächlichen Code nebst einer Beispieleingabe zeigen.

joma1234

(Themenstarter)

Anmeldungsdatum:
2. Juli 2019

Beiträge: Zähle...

Text file bla enthält folgende Zeilen:

M3.S.18
1 2 3 4
4 6 7 9
end

M3.S.18.6
1 2 3 4
4 6 7 9
end

Output awk '/M3.S.18/,/end/' bla

M3.S.18
1 2 3 4
4 6 7 9
end
M3.S.18.6
1 2 3 4
4 6 7 9
end

Output awk '/M3.S.18$/,/end/' bla

M3.S.18
1 2 3 4
4 6 7 9
end
 

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

Da fehlt immer noch die Eingabe. Was man aber schon mal sagen kann: Du musst das Dollarzeichen, das der Anker für die Zeilenenden ist, escapen und nicht das Dollarzeichen, das zur Variablenexpansion gehört. Und der Zeilenendeanker muss natürlich am Ende des Musters stehen.

joma1234

(Themenstarter)

Anmeldungsdatum:
2. Juli 2019

Beiträge: Zähle...

Meine Eingabe ist (nicht ganz sicher was du genau möchtest) : script M3.S.18

Im Script selbst hab ich dann die Zeilen:

1
2
3
echo $1 |awk '{print "set rule = " $1 }' > rel_rule
source rel_rule
awk "/\$rule/,end/" bla

Wenn ich es so mache bekomme ich als Output:

M3.S.18
1 2 3 4
4 6 7 9
end
M3.S.18.6
1 2 3 4
4 6 7 9
end

Aber ich möchte die Sektion von "M3.S.18.6" nicht bekommen.

Bearbeitet von rklm:

Syntaxhighlighting. Bitte beachte Forum/Syntax und nutze die Vorschaufunktion.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

joma1234 schrieb:

1
2
3
echo $1 |awk '{print "set rule = " $1 }' > rel_rule
source rel_rule
awk "/\$rule/,end/" bla

Was denkst Du, dass das macht? Weder in der sh noch in der bash führt die Zeile mit "set rule = ..." dazu, dass eine Shell-Variable gesetzt wird. Welche Shell nutzt Du denn für das Skript? Das ganze ist aber auch total überflüssig, weil Du $1 direkt verwenden kannst. Und, wie schon gesagt, hast Du das falsche Dollarzeichen escaped.

1
awk "/$1\$/,end/" bla

Um es sauber zu machen, müsste man allerdings den Inhalt der Variable escapen, weil sonst nämlich "/" u.a. zu Problemen führen.

Ein anderer Ansatz ohne Regex:

1
awk -v "begin=$1" '$0==begin,/end/' bla

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

Oder als CLI-Programm in Python3, das einem verrät, was es tut:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python3
import argparse

parser = argparse.ArgumentParser(
    description="filter blocks with given name(s) from file(s)"
)
parser.add_argument(
    "-n",
    "--filter-name",
    dest="filter",
    action="append",
    help="block name to filter for",
)
parser.add_argument(
    "files",
    metavar="FILE"
    nargs="+",
    help="file(s) to filter"
)
args = parser.parse_args()

on_block = False
for input_file in args.files:
    with open(input_file) as f:
        for line in f:
            _line = line.rstrip()
            if _line in args.filter:
                on_block = True
            if on_block:
                print(line, end="")
                if _line == "end":
                    on_block = False
$ ./filter_blocks.py -h
usage: filter_blocks.py [-h] [-n FILTER] FILE [FILE ...]

filter blocks with given name(s) from file(s)

positional arguments:
  FILE                  file(s) to filter

optional arguments:
  -h, --help            show this help message and exit
  -n FILTER, --filter-name FILTER
                        block name to filter for 
$ ./filter_blocks -n 'M3.S.18' bla
M3.S.18
1 2 3 4
4 6 7 9
end 

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17630

Bei mir erwartet awk nicht, dass ich den Zeilenende-Dollar-Anker maskiere:

1
2
3
4
5
n=18; awk "/M3.S.$n$/,/end/" m3.dat 
M3.S.18
1 2 3 4
4 6 7 9
end

Man beachte: Um $n zu interpretieren müssen doppelte, nicht einfache Anführungsstriche verwendet werden.

Antworten |