[NZLUG] udev shell (or awk or ...) one-liner puzzle

Martin D Kealey martin at kurahaupo.gen.nz
Sat Jul 9 01:40:12 NZST 2016


Depending on whether you literally mean "digits after excluding all other
characters", or numeric groups separated by underscores, there are
slightly different answers.

If you mean groups separated by underscores, use this:

  IFS=_ read -ra x <<<$ID_PATH_TAG && echo VSCOM_PORT_IDX=$(( x[-3] * 4 + x[-1] - 8 ))

If you mean ignore the non-digits and just use what's left, use this:

  x=${ID_PATH_TAG//[!0-9]/} ; echo VSCOM_PORT_IDX=$(( ${x:(-3):1} * 4 + ${x:(-1):1} - 8 ))

or if you prefer:

  x=${ID_PATH_TAG//[!0-9]/} ; x=10#${x:(-3)} ; echo VSCOM_PORT_IDX=$(( x/100 * 4 + x%10 - 8 ))

And if you're sure that there won't be too many digits (thus avoiding
integer overflow), this is a bit simpler:

  x=10#${ID_PATH_TAG//[!0-9]/} ; echo VSCOM_PORT_IDX=$(( x/100%10 * 4 + x%10 - 8 ))

If you want to take care of both the cases of too few and too many digits,
it gets a bit messy:

  x=000${ID_PATH_TAG//[!0-9]/} ; x=10#${x:(-3)} ; echo VSCOM_PORT_IDX=$(( x/100 * 4 + x%10 - 8 ))

NB: negative indexing isn't supported on older versions of Bash. For those
you'd need ${x:${#x}-3} or x[${#x[@]}-3]

-Martin

On Fri, 8 Jul 2016, Eliot Blennerhassett wrote:
> Greetings,
>
> Preface: This is a puzzle for those who like the challenge.  I already
> have a workable solution.
>
> Problem:
> I'm looking for a one-liner 'program' that is usable for the
> IMPORT{program} part of this udev rule (I'd like to avoid having to
> install the helper script, but maybe I can't...)
>
> SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011", \
> IMPORT{program}="/usr/local/sbin/vscom_id_to_index.py $env{ID_PATH_TAG}"
>
> The invocation of the program needs to work when placed between double
> quotes. So it can't itself contain those quotes...
>
> $env{ID_PATH_TAG} is substituted with something resembling
> pci-0000_00_1a_0-usb-0_1_2_2_1_0
> pci-0000_00_1a_0-usb-0_1_2_4_3_1_3
>
> The program should calculate '
> value = (3rd_to_last_digit - 2) * 4 + last_digit)
> and output VSCOM_PORT_IDX=<value>v
>
> for the examples above, the output should be
> VSCOM_PORT_IDX=0
> VSCOM_PORT_IDX=7
> respectively
>
> Currently, I'm using an external python script.
> vscom_id_to_index.py =
>
> def id_to_idx(s):
>     f = s.split('_')
>     n1 = int(f[-1])
>     n3 = int(f[-3])
>     return (n3 - 2) * 4 + n1
>
>
> if __name__ == '__main__':
>     import sys
>     usb_id = sys.argv[1]
>     print('VSCOM_PORT_IDX={}'.format(id_to_idx(usb_id)))
>
>
> Background:
> This is to give consistent aliases for the ports of some 8-port usb
> serial interfaces,this is done by generating symlinks based on device
> serial number plus a port index calculated as above:
>
> SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011",
> IMPORT{program}="/usr/local/sbin/vscom_id_to_index.py $env{ID_PATH_TAG}"
>
> SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6011",
> ENV{ID_SERIAL_SHORT}=="?*",
> SYMLINK+="vscom%E{ID_SERIAL_SHORT}_%E{VSCOM_PORT_IDX}"
>
> which give fixed aliases to ttyUSB?? that refer to a fixed port no
> matter the enumeration order or usb topology.
>
> Like this:
>
> /dev/vscomFT97WJKL_0  /dev/vscomFT97WJKL_4  /dev/vscomFT97WK0I_0
> /dev/vscomFT97WK0I_4
> /dev/vscomFT97WJKL_1  /dev/vscomFT97WJKL_5  /dev/vscomFT97WK0I_1
> /dev/vscomFT97WK0I_5
> /dev/vscomFT97WJKL_2  /dev/vscomFT97WJKL_6  /dev/vscomFT97WK0I_2
> /dev/vscomFT97WK0I_6
> /dev/vscomFT97WJKL_3  /dev/vscomFT97WJKL_7  /dev/vscomFT97WK0I_3
> /dev/vscomFT97WK0I_7
>
>
> --
> Eliot
> _______________________________________________
> NZLUG mailing list
> NZLUG at lists.nzoss.org.nz
> http://lists.nzoss.org.nz/mailman/listinfo/nzlug
>


More information about the NZLUG mailing list