3

As a first project for learning awk, I wanted to reformat the output of the wmctrl command, which can be installed like this in Debian 11:

sudo apt install wmctrl

To list information about all the windows I have open, I run this command:

wmctrl -lpG

Sample Output:

0x0120002b  4 7      2    157  3836 2068 my-pc window - AWK - Dealing with spaces in the last column of output from wmctrl - Unix & Linux Stack Exchange — Firefox

I never can remember what each column means, in the command above, so I wanted to break it apart into name/value pairs, using AWK:

wmctrl -lpG | awk '{print "----------------------\nWindow ID: " $1 "\nDesktop Number: " $2 "\nProcess ID: " $3 "\nx-offset: " $4 "\ny-offset: " $5 "\nwidth: " $6 "\nheight: " $7 "\nMachine Name: " $8 "\nWindow Title: " $9}'

Sample Output:

----------------------
Window ID: 0x0120002b
Desktop Number: 4
Process ID: 7
x-offset: 2
y-offset: 134
width: 3836
height: 2068
Machine Name: my-pc
Window Title: window

Desired Output:

----------------------
Window ID: 0x0120002b
Desktop Number: 4
Process ID: 7
x-offset: 2
y-offset: 134
width: 3836
height: 2068
Machine Name: my-pc
Window Title: window - AWK - Dealing with spaces in the last column of output from wmctrl - Unix & Linux Stack Exchange — Firefox

However, I'm having trouble figuring out how to handle the 9th Column outputted by wmctrl -lpG (because the 9th column contains spaces). Notice that I'm only getting the first word of the window title instead of the whole window title.

Is there an easy way to remedy this issue?

Lonnie Best
  • 4,895
  • 6
  • 27
  • 42

3 Answers3

3
wmctrl -lpG \
| awk '{
         tmp=$0;
         # remove first 8 fields from tmp
         sub(/^[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ /,"",tmp);
         print "----------------------\nWindow ID: " $1 "\nDesktop Number: " $2 "\nProcess ID: " $3 "\nx-offset: " $4 "\ny-offset: " $5 "\nwidth: " $6 "\nheight: " $7 "\nMachine Name: " $8 "\nWindow Title: " tmp
       }'

Output:

----------------------
Window ID: 0x0120002b
Desktop Number: 4
Process ID: 7
x-offset: 2
y-offset: 157
width: 3836
height: 2068
Machine Name: sidekick
Window Title: window - AWK - Dealing with spaces in the last column of output from wmctrl - Unix & Linux Stack Exchange — Firefox
Cyrus
  • 12,059
  • 3
  • 29
  • 53
  • Yes, as you suggested it's possibe to replace `/^[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ +[^ ]+ /` with `/^[^ ]+( +[^ ]+){7} /`. – Cyrus Dec 27 '21 at 23:00
  • `sub(/^([^\s]+\s+){8}/,"",tmp)` is what I'm trying right now. Let try what you suggest above instead. – Lonnie Best Dec 27 '21 at 23:07
  • I apparently don't understand what sub is doing. I tested my regular expression `/^([^\s]+\s+){8}/` [here](https://regexr.com/) and it works, but not with `sub`. – Lonnie Best Dec 27 '21 at 23:10
  • @Quasímodo : Do you know why my regular expression doesn't work, but Cyrus' does? – Lonnie Best Dec 27 '21 at 23:14
  • @Quasímodo What is the most standard compliant Regular Expression software in Linux? Maybe I should learn that instead of AWK. – Lonnie Best Dec 27 '21 at 23:18
  • 2
    @LonnieBest the POSIX standard defines 2 types of regular expression, Basic (BREs) and Extended (EREs). grep and sed use BREs by default and EREs when called with the `-E` argument (which all greps but only some seds support). awk only uses EREs. There is a third type of regexp, Perl-compatible (PCREs), but that is not defined by the POSIX standard and much less efficient than BREs/EREs. Many versions of tools (e.g. GNU tools) in addition to supporting the POSIX standards also have extensions to provide additional functionality including defining and implementing constructs undefined by POSIX. – Ed Morton Dec 28 '21 at 13:02
  • 2
    So when you ask `What is the most standard compliant Regular Expression software in Linux` - the specific answer to that is IMHO tools that support POSIX EREs as those are supported by mandatory POSIX tools (which excludes any tool that uses PCREs) that must be present on any Unix box and EREs will work in all greps and awks (and you can do anything useful with awk that you can do with sed or grep). Practically, though, many of us rely on GNU extensions these days and in particular GNU awk is the version of awk that has the most useful features/extensions for manipulating text. – Ed Morton Dec 28 '21 at 13:07
3

It looks like the output of wmctrl is fixed width fields so you could use GNU awk for FIELDWIDTHS. Using cat file since I don't have wmctrl and retaining your original print statement:

$ wmctrl -lpG |
awk -v FIELDWIDTHS='10 3 2 7 7 7 5 6 *' '
{
    for (i=1;i<=NF;i++) {
        gsub(/^ +| +$/,"",$i)
    }
    print "----------------------\nWindow ID: " $1 "\nDesktop Number: " $2 "\nProcess ID: " $3 "\nx-offset: " $4 "\ny-offset: " $5 "\nwidth: " $6 "\nheight: " $7 "\nMachine Name: " $8 "\nWindow Title: " $9
}'
----------------------
Window ID: 0x0120002b
Desktop Number: 4
Process ID: 7
x-offset: 2
y-offset: 157
width: 3836
height: 2068
Machine Name: my-pc
Window Title: window - AWK - Dealing with spaces in the last column of output from wmctrl - Unix & Linux Stack Exchange — Firefox

Alternatively, using any awk:

$ wmctrl -lpG |
awk '
    BEGIN {
        OFS = ": "
        numCols = split("Window ID:Desktop Number:Process ID:x-offset:y-offset:width:height:Machine Name:Window Title",hdr,/:/)
    }
    {
        print "----------------------"
        for (i=1; i<numCols; i++) {
            print hdr[i], $i
        }
        sub("([^ ]+ +){"i-1"}","")
        print hdr[i], $0
    }
'
Lonnie Best
  • 4,895
  • 6
  • 27
  • 42
Ed Morton
  • 28,789
  • 5
  • 20
  • 47
2

This is a possibility:

$ wmctrl -lpG | awk '{
  a="";
  for(i=9; i<=NF; i++) { 
    a = a " " $i
  };
  print "----------------------\nWindow ID: " $1 "\nDesktop Number: " $2 "\nProcess ID: " $3 "\nx-offset: " $4 "\ny-offset: " $5 "\nwidth: " $6 "\nheight: " $7 "\nMachine Name: " $8 "\nWindow Title: " a }'
----------------------
Window ID: 0x04000007
Desktop Number: 0
Process ID: 18952
x-offset: 1367
y-offset: 102
width: 1600
height: 836
Machine Name: pc
Window Title:  ~:bash—Konsole
...
Cyrus
  • 12,059
  • 3
  • 29
  • 53
schrodingerscatcuriosity
  • 12,087
  • 3
  • 29
  • 57
  • 2
    Nitpick: This is clever, but if a window title contained multiple consecutive spaces, or any tab, they would be merged into a single space. – Quasímodo Dec 27 '21 at 23:09