awk -- Bereichsdefinition bei Feld-Adressierung

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
zongo
Beiträge: 117
Registriert: 09.04.2007 23:53:46

awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von zongo » 19.12.2011 12:38:15

Hallo!

Gibt es in (g)awk eine einfache Möglichkeit Bereichsdefinitionen für Felder anzugeben(äquivalent zu zur Shell bspw. : cut -f2-4, 5-)?

Den Terminus $x-$NF scheint es in der Form nicht zu geben. Muss ich, wenn ich bspw. ab $5 bis zum letzten Feld $NF(wobei ich vorher nicht weiß wieviele Felder eine Zeile hat) eine Schleife benutzen oder gibt es eine andere Art zu sagen "Gib mir ab hier alles bis zum Schluss"?

Es geht so vieles in awk, aber das anscheinend nicht, oder doch?

Liffi
Beiträge: 2345
Registriert: 02.10.2004 01:33:05

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von Liffi » 19.12.2011 13:32:25

Hier das koennte dir weiterhelfen.

EDIT:: Und nein, ganz so einfach wie bei cut geht es afair nicht.

Benutzeravatar
zongo
Beiträge: 117
Registriert: 09.04.2007 23:53:46

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von zongo » 19.12.2011 14:16:29

Mmmh, hätte ich jetzt nicht gedacht. War mir sicher, das ich nur den Wald vor lauter Bäumen nicht sehe.
Socket-Programmierung via TCP/IP(in einer Sprache zur Listenverabeitung!!) geht mit gawk aber keine simple Von-Bis-Feldadressierung ... Sachen gibt´s :roll:

uname
Beiträge: 12414
Registriert: 03.06.2008 09:33:02

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von uname » 19.12.2011 16:28:00

Vielleicht kannst du als Alternative noch "split" nutzen. Wirklich schön oder besser ist es aber wohl nicht.

Code: Alles auswählen

awk < datei '{max=split ($0,a," "); for ( i=1 ; i<=max ; i++ ) { print i ":" a[i] }}'

yeti

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von yeti » 20.12.2011 02:00:35

zongo hat geschrieben:Socket-Programmierung via TCP/IP(in einer Sprache zur Listenverabeitung!!) geht mit gawk aber keine simple Von-Bis-Feldadressierung ... Sachen gibt´s :roll:
gawk ist ja auch GNUnsinn... ...und GNUnsinn kann immer Alles außer den Dingen die man wirklich braucht... :P

...ok... Index-Ranges sind nicht Bestandteil der üblichen awk-Sprachdefinitionen... und ich würd es auch nicht benutzen wenn ein GNUnsinniges Tool es kann aber der Rest der Welt überwiegend nicht... ich sitz' halt doch hin und wieder vor einem echten Unix ohne GNUtilities...

yeti

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von yeti » 20.12.2011 02:27:18

Code: Alles auswählen

$ echo a b c d e f g h i j | awk '{ for ( i=1 ; i<=NF ; i++ ) print i ":" $i }'
1:a
2:b
3:c
4:d
5:e
6:f
7:g
8:h
9:i
10:j
Ne nette Lösung für Ranges so wie bei cut angebbar ist aber auch damit nimmer sinnig in einer Zeile zu erschlagen...

Man könnte die auszugebenden/bearbeitenden Felder durch einen Quasi-Bitstring angeben ...

Code: Alles auswählen

$ echo a b c d e f g h i j | awk '{ split("011100101",a,"") ; for ( i=1 ; i<=NF ; i++ ) if( a[i] ) print i ":" $i }'
2:b
3:c
4:d
7:g
9:i
... aber das ist noch weit von der Syntax der Angabe bei cut entfernt. Für awk-Einzeiler wird es vermutlich keine deutlich einfache Lösung geben, aber einen String mit Angaben à la "2-4,7,9" zu parsen und daraus dieses Helferfeld bauen ist mit awk durchaus drin. Es lohnt sich nur das mal durchzuziehen wenn es öfter mal in komplexeren Skripten gebraucht wird...

...womit ich natürlich nicht die Existenz anders aufgebauter Lösungen verneinen will... die wird es auch noch zuhauf geben!

yeti

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von yeti » 20.12.2011 04:07:04

Code: Alles auswählen

$ echo a b c d e f g h i j | mawk '{ e=split("1,3-5,7-",E,",") ; for( i=1 ; i<=e ; i++ ) { if( match(E[i],"-$") ) { from=substr(E[i],1,RSTART-1) ; to=NF } else if( match(E[i],"-") ) { from=substr(E[i],1,RSTART-1) ; to=substr(E[i],RSTART+1) } else { from=to=E[i] } ; from=int(from) ; to=int(to) ; for( n=from ; n<=to ; n++ ) print n":"$n } }'
1:a
3:c
4:d
5:e
7:g
8:h
9:i
10:j
... das macht als Einzeiler schon keinen Spaß mehr. Da müsste dann am Besten noch ein bissl Fehlerbehandlung dazu und dann könnte es sich für komplexere Skripte vielleicht ganz nett machen... aber für den schnellen Hack in der Commandline ist's nix mehr...

Aufgedröselt schaut das schon netter aus ...

Code: Alles auswählen

(yeti@xs3:4)~$ cat xxx.awk 
#!/usr/bin/mawk -f
{
        e=split("1,3-5,7-",E,",")
        for( i=1 ; i<=e ; i++ ) {
                if( match(E[i],"-$") ) {
                        from=substr(E[i],1,RSTART-1)
                        to=NF
                } else if( match(E[i],"-") ) {
                        from=substr(E[i],1,RSTART-1)
                        to=substr(E[i],RSTART+1)
                } else from=to=E[i]
                from=int(from)
                to=int(to)
                for( n=from ; n<=to ; n++ ) print n":"$n
        }
}
(yeti@xs3:4)~$ chmod 755 xxx.awk 
(yeti@xs3:4)~$ echo a b c d e f g h i j | ./xxx.awk 
1:a
3:c
4:d
5:e
7:g
8:h
9:i
10:j
... das kann dann auch ohne Knoten im Hirn fast schon im ersten Anlauf verstehen... :-D

Benutzeravatar
Meillo
Moderator
Beiträge: 9241
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von Meillo » 21.12.2011 13:26:12

Cool, ein awk-Thread. :-)


Yeti hat ja schon kraeftig vorgelegt, aber ich hab auch noch was zu bieten.

Wie waer's damit:

Code: Alles auswählen

echo a b c d e f g h i j |
awk '{ "echo \""$0"\" | cut -d\" \" -f1,4-5,9-" | getline; print }'
... nur als Ansatz.

Wenn du Bereiche wie bei cut(1) willst, dann verwendest du am besten auch cut.


yeti hat geschrieben:

Code: Alles auswählen

split("011100101",a,"")
Hier musst du aufpassen, denn laut POSIX ist das Verhalten undefiniert wenn das dritte Argument der leere String ist:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html hat geschrieben: split(s, a[, fs ])
Split the string s into array elements a[1], a[2], ..., a[n], and return n. All elements of the array shall be deleted before the split is performed. The separation shall be done with the ERE fs or with the field separator FS if fs is not given. Each array element shall have a string value when created and, if appropriate, the array element shall be considered a numeric string (see Expressions in awk ). The effect of a null string as the value of fs is unspecified.
Aber es wird auch schon angedeutet:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html hat geschrieben: Unspecified behavior when split( string, array, <null>) is used is to allow a proposed future extension that would split up a string into an array of individual characters.
Use ed once in a while!

yellowblue
Beiträge: 16
Registriert: 14.10.2011 11:09:56

Re: awk -- Bereichsdefinition bei Feld-Adressierung

Beitrag von yellowblue » 13.01.2012 16:09:51

Exemplarische Alternative in perl:

perl -n -a -F: -e ' $lf=@F-1; print "@F[0,3..$lf]" ' /etc/passwd

(Und vielleicht war genau das Problem der Anlass warum Larry Wall damals Perl erfand als er mit awk mal wieder nicht weiterkam ... :wink: )

Eine Anmerkung noch:
Wenn man bis zum letzten Feld "printet" dann hängt ja i.d.R. das "\n" bereits am letzten Feld und man muss sich nicht darum kümmern. Adressiert man aber bspw. @F[4..$lf-1] d.h. bis zum vorletzten Feld, dann muss man das "\n" bei der Ausgabe noch dranhängen(oder anderweitig für den Zeilenumbruch sorgen).

Antworten