linuxbashawkusblsusb

AWK error - syntax error at or near grep


I need to create a script to unbind/bind all usb in one linux machine.

For this I need to run:

lsusb -t wich returns:

root@lsdg7sd-fc:~# lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/10p, 12M
    |__ Port 4: Dev 2, If 0, Class=vend., Driver=ftdi_sio, 12M
    |__ Port 6: Dev 4, If 0, Class=HID, Driver=usbhid, 1.5M
    |__ Port 6: Dev 4, If 1, Class=HID, Driver=usbhid, 1.5M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/10p, 480M

Now, for this example I need to run:

 // disable the bus 1, port 1
 echo '2-4' | tee /sys/bus/usb/drivers/usb/unbind
 // disable the bus 1, port 2
 echo '2-6' | tee /sys/bus/usb/drivers/usb/unbind
 // enable the bus 1, port 1
 echo '2-4' | tee /sys/bus/usb/drivers/usb/bind
 // enable the bus 1, port 2
 echo '2-6' | tee /sys/bus/usb/drivers/usb/bind

In order to achieve this by creating a script (I am very new to linux), I did the following:

#!/bin/bash

lsusb -t | awk '{

bus="";
if($1=="|__")
      print "Child USB Port: ",$3;
else if ($1=="/:") {
      print $3;
      var= $(echo $3 | grep -o "[1-9]");
      echo $var;
}
}'

var=`echo "02.Port" | grep -o "[1-9]"`;
echo $var;
var=`echo "02.Port" | grep -o "[0-9]\{2\}"`;
echo $var;

I tried all the possible combinations in order to set var. I always get an error.

awk: line 8: syntax error at or near grep

Can anyone suggest a solution or another approach?

Thanks for reading.

---------------------- Update

Thanks Ed Morton, the input is the result of the command lsusb -t: (at my end)

/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/10p, 12M
    |__ Port 4: Dev 2, If 0, Class=vend., Driver=ftdi_sio, 12M
    |__ Port 6: Dev 4, If 0, Class=HID, Driver=usbhid, 1.5M
    |__ Port 6: Dev 4, If 1, Class=HID, Driver=usbhid, 1.5M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/10p, 480M

And I want to parse this information in order to get the BUS number and the port number. So the output should be:

2-1
2-4
2-6
2-6
1-1

But, I only need the "child" ports, so I need the following output:

2-4
2-6
2-6

Thanks again!


Solution

  • shell is an environment from which to call UNIX tools, with a language to sequence those calls.

    grep is a UNIX tool to print lines from files (or pipes) that match regular expressions.

    awk is the standard general-purpose UNIX tool for processing text.

    They are 3 completely different tools with their own languages/syntax.

    You would call grep from shell to find a regexp and print the matching line.

    You would call awk from shell to do more complicated text-manipulation operations which may or may not including anything that grep can do.

    You would NOT call grep from awk and you CANNOT call awk from grep.

    You can call shell from awk in some very rare situations where that is useful but you cannot call shell from grep.

    You posted some sample input in your question, now update it to show the specific output you would like to get as a result of running a tool on that input so we can help you write the tool to do that.

    In case it's useful, here is the correct awk syntax for an awk script to do what you are trying to do with echo and grep, etc.:

    $ cat tst.awk
    {
        if (/\|__/) {
            print "Child USB Port: ",$3
        }
        else {
            print $3
            var = $3
            gsub(/[^[:digit:]]/,"",var)
            print var
        }
    }
    $
    $ awk -f tst.awk file
    02.Port
    02
    Child USB Port:  4:
    Child USB Port:  6:
    Child USB Port:  6:
    01.Port
    01
    

    Given your updated question:

    $ cat tst.awk
    {
        var = $3+0
        if (/\/:/) {
            bus = var
        }
        else {
            print bus "-" var
        }
    }
    $
    $ awk -f tst.awk file
    2-4
    2-6
    2-6
    

    Note that if you want that to go to a couple of files as well as stdout then all you need instead of a subsequent echo+pipe+tee is:

    BEGIN{
        path   = "/sys/bus/usb/drivers/usb/"
        unbind = path "unbind"
        bind   = path "bind"
    }
    {
        var = $3+0
        if (/\/:/) {
            bus = var
        }
        else {
            busPort = bus "-" var
            print busPort
            print busPort > unbind
            print busPort > bind
        }
    }
    

    and since it seems pointless to repeat the action for bus+port combinations you've already processed (e.g. the second 2-6):

    BEGIN{
        path   = "/sys/bus/usb/drivers/usb/"
        unbind = path "unbind"
        bind   = path "bind"
    }
    {
        var = $3+0
        if (/\/:/) {
            bus = var
        }
        else {
            busPort = bus "-" var
            if (!seen[busPort]++) {
                print busPort
                print busPort > unbind
                print busPort > bind
            }
        }
    }