1

In trying to understand and apply the accepted answer to How to make a program that finds ids of XInput devices, I'm finding code that doesn't appear to comply with the documented syntax for bash.

  • ~ is documented as bitwise negation -- a mathematical operator taking only one argument -- but it's being run here with $0 as one argument and a string as the other.
  • $0 is documented as referring to the name that the script itself was started with, but referring to that name doesn't make sense in the context of what this code is supposed to do.

What am I missing here?

ids=$(xinput --list | awk -v search="$SEARCH" \
'$0 ~ search {match($0, /id=[0-9]+/);\
              if (RSTART) \
                print substr($0, RSTART+3, RLENGTH-3)\
             }'\
 )
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
rado
  • 5,720
  • 5
  • 29
  • 51
  • 1
    (1) - Scripts don't start with a completely set of variables; variables are initialized from the environment -- so you can run `var=val ./yourscript`, and it'll start with `var` having the value `val`. (Note that lower-case names are best practice for your own variables to avoid conflicting with variables having meaning to the shell or OS; see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, fourth paragraph). – Charles Duffy May 24 '17 at 17:04
  • 1
    (2) That's awk syntax, not bash syntax. Perhaps you should be in the awk tag? `~` is actually a regex operator in that context. I'd also advise against using the ABS as a reference, ever, for anything -- it's very much the bash equivalent to W3Schools, having lots of Google juice but full of bad-practice examples and misinformation. The [bash-hackers wiki](http://wiki.bash-hackers.org/), the [Wooledge wiki](http://mywiki.wooledge.org/BashGuide), and the official manual are much more reliable. – Charles Duffy May 24 '17 at 17:04
  • Thanks for all this new information. Do you have any explanation on `$0` usage? – rado May 24 '17 at 17:07
  • 1
    Yup -- in awk (not bash!), `$0` refers to the entire line being processed. This is very much a case where you have a program in one language embedded inside another program in a different language, so have to look at the contexts independently. – Charles Duffy May 24 '17 at 17:08
  • I think it all sums up to recognize awk context inside bash. Thanks for clarifying. Well, if you don't care, could you get this comments together into an answer for acceptance? – rado May 24 '17 at 17:11
  • Hmm. I'd like to figure out how to improve the question -- right now, I'm commenting as opposed to answering because I'm not sure the question meets site guidelines on scope. OTOH, if the comments above answer your question, I think that provides some guidance on how to edit it down to allow something that's narrow and responsive; might take a shot if you don't mind. – Charles Duffy May 24 '17 at 17:13

2 Answers2

5

awk is a different programming language, with its own syntax. The string being passed to awk is thus parsed as code in the awk language, rather than as bash.

In awk (but not bash):

  • $0 refers to the complete text of the line being processed.
  • ~ is a regex operator; text ~ regex is a boolean operation which has a truthy result if the text matches the regex.
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
1

I was going to post this on your follow up question which has been flagged as duplicate. You asked in that question what this script was doing. This entire script can be broken down like:

  1. We are setting the variable ids to the following
  2. Take the output from xinput --list and pipe it to awk
  3. Before starting the awk script set awk variable search to shell variable $SEARCH. So a $SEARCH needs to be set first. -v search="$SEARCH"
  4. Processing each record, test to see if anywhere in the entire record ($0) the value stored in variable search is found. If so, proceed.
  5. Using match() test the entire record ($0) again, but this time with regex string id=[0-9]+ which would be a string containing id= followed by 1 or more numbers. Match will set awk variable RSTART with the starting position of the match.
  6. if RSTART is set, then a match was found, so...
  7. Print the substring of the entire record ($0) starting three characters after match was found (in this case after id=) for the length of the match RLENGTH minus 3 characters. Essentially whatever numbers are found after the id.

So stating this in english. Set variable $SEARCH to something that you are searching for in the output of xinput --list. This awk script will find the line that matches that search string. It will look for an id=<some numbers> on the same line of the xinput --list output and return those numbers.

An example:

If xinput --list spits out the following two lines:

This is the first line of xinput --line and the id=12345
This is the second line of xinput --line and the id=67891

If you set SEARCH="second" and then executed this statement it would output 67891 and store it in variable ids.

JNevill
  • 46,980
  • 4
  • 38
  • 63
  • I've tried to edit that other question to make it obviously non-duplicative. If you'd care to weigh in on the reopen vote... – Charles Duffy May 24 '17 at 20:30
  • Upvoted the unclose. Thanks for editing it. I just stuck this here in hopes it helps OP since that is a confusing line of code if you haven't encountered awk before. – JNevill May 24 '17 at 20:36
  • The other is reopened, if you want to move this there. – Charles Duffy May 24 '17 at 21:44