Jump to content

Advice for a simple startup script [solved]


Recommended Posts

'ning,

 

So I had some problems with my touchpad driver, and at present my fix is to manually fix some of the settings using the synclient program (shared-memory config client for the Synaptics touchpad driver for X). For background, look here:

 

https://mandrivausers.org/index.php?showtop...39entry184939

 

I need to issue a series of commands of the syntax

 

synclient <Option>=<value>

 

Rather than rewriting the values in the script every time I tinker with xorg.conf, I'd like it to actually read the values from xorg.conf and use them for the commands needed at runtime.

 

I'm not even quite sure what tools/commands are best to do this. I know there are some string-filtering functions built into the shell, but are they sufficient? I once tried to use sed on Windows, and didn't even get my head round the manual.

 

Here, I guess, is what the script must do:

 

1 - run the command: synclient -l (to get the actual runtime values) into a pipe or temp file

2 - Read the option-name and value from each line generated by (1), possibly into an associative array or a pair of numeric arrays

3 - For each option, find the corresponding line in xorg.conf (if the line exists - some will not) and read the value

4 - If the values do not match, issue: synclient <option-name>=<value-from-xorg.conf>

 

It sounds simple to my mind, but I don't know how to go about the string-parsing part in this environment. Can anyone help?

Link to comment
Share on other sites

I assume synclient -l gives output lines looking like "option=value" (without quote).

sed -n '/^[[:blank:]]*Identifier[[:blank:]]*"SynapticsMouse1"[[:blank:]]*$/,/^[[:blank:]]*EndSection
[[:blank:]]*$/s/^[[:blank:]]*Option[[:blank:]]*"\([^="]*\)"[[:blank:]]*"\([^"]*\)"[[:blank:]]
*$/=\1=\2/p' | grep -Ff <(synclient -l | sed -n 's/^\([^=]*\)=.*$/=\1=/p') | sed 's/^=//' | grep -vFxf <(synclient -l) | while read cmd; do eval synclient "'${cmd}'"; done

 

This is a rough try. A better solution might be needed if synclient -l is long to execute (as it is executed twice here), and besides, there's no way I can test any of this.

 

Yves.

Link to comment
Share on other sites

Hi Yves, thanks for the quick reply!

 

Blimey, is that all one line? no wonder I got scared off with sed earlier...

 

The synclient command is really quick in the terminal, so no problem there. And you're correct about the output format, apart from some spaces and tabs and the first line. The second code box in the linked post above is the exact output.

 

so how do I specify /etc/X11/XF86Config as the file to be read from?

Link to comment
Share on other sites

Okay, I bit the bullet and tried reading up a little on sed (not from the manpage, it's hopeless, but from some of the linked docs on the homepage). Still haven't understood much, but this does the trick for outputting a 'clean' list of option-value pairs from synclient:

 

synclient -l | grep = | sed 's/[ ]//g'

 

Guess doing the same for XF86Config is a fair bit harder, which is what the above is for? Will keep playing and see what I learn.

Link to comment
Share on other sites

Blimey, is that all one line?  no wonder I got scared off with sed earlier...

The synclient command is really quick in the terminal, so no problem there.  And you're correct about the output format, apart from some spaces and tabs and the first line.  The second code box in the linked post above is the exact output.

so how do I specify /etc/X11/XF86Config as the file to be read from?

 

I'll try and explain. I wrote that in a bit of a hurry, and indeed, I forgot to write the name of the file to read from :lol:

 

sed -n '/^[[:blank:]]*Driver[[:blank:]]*"synaptics"[[:blank:]]*$/,/^[[:blank:]]*EndSection[[:blank:]]*$/

tells sed to not output anything by default (-n), and look for the part of the text that starts with 'Driver "synaptics"' (small change here, more reliable I think), and ends with 'EndSection'. The '[[:blank:]]*' everywhere are there to be "blank-proof", in case you use tabs or spaces.

Now if this block is found, for each line inside sed executes:

s/^[[:blank:]]*Option[[:blank:]]*"\([^="]*\)"[[:blank:]]*"\([^"]*\)"[[:blank:]]*$/=\1=\2/p' /etc/X11/XF86Config

(file added :) ) a line is printed only if it matches '"Option" = "Value"', with all spaces removed, and with an '=' added as first character (this is because next grep will work without regular expressions, and we want to find the start of line).

 

Then grep filters the result so:

grep -Ff <(synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=.*$/=\1=/p')

which means that only lines that start with an option known to synclient are kept. The notation '<()' is a bash notation to view a subprocess' output as if it were a file.

Now we don't need the initial '=' so it is easily removed.

Finally, grep filters the result by removing all options that are already set (as reported by synclient):

grep -vFxf <(synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=[[:blank:]]*\([^[:blank:]]*\)[[:blank:]]*$/\1=\2/p')

Option -v is to exclude, -F is to search text instead of regexps, -x is to have only full lines, and -f is to select the file where forbiden lines are stored, and is the result of reformating synclient output (blanks now taken into account).

 

Which just leaves to execute each remaining command:

while read cmd; do eval synclient "'${cmd}'"; done

 

The full line can be written in your startup script, and broken into lines for better readability:

... whatever is already there in the file ...

[1]sed -n '
[2]  /^[[:blank:]]*Driver[[:blank:]]*"synaptics"[[:blank:]]*$/,/^[[:blank:]]*EndSection[[:blank:]]*$/ {
[3]    s/^[[:blank:]]*Option[[:blank:]]*"\([^="]*\)"[[:blank:]]*"\([^"]*\)"[[:blank:]]*$/=\1=\2/p
[4]  }
[5]' /etc/X11/XF86Config \
[6]| grep -Ff <(synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=.*$/=\1=/p') \
[7]| sed 's/^=//' \
[8]| grep -vFxf <(synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=[[:blank:]]*\([^[:blank:]]*\)[[:blank:]]*$/\1=\2/p') \
[9]| while read cmd; do eval synclient "'${cmd}'"; done

[edit:]I added line numbers above between brackets, so that you know where each line starts.[/edit]

 

I still can't test, though...

 

Yves.

Edited by theYinYeti
Link to comment
Share on other sites

Thanks for the detailed explanation, Yves. I do want to learn how to use these commands myself, not just grab a script off the shelf, so I appreciate you breaking it down for me so I can see what's what.

 

I'm going to see if I can add what I learned overnight to what you have given me, because I just realised it might be wise for me to only read a smaller chunk of the XF86Config (from below the 'SHMConfig' line). I think I can do that now, but I'll post back what I come up with and if it works.

Link to comment
Share on other sites

Thanks for the detailed explanation, Yves. I do want to learn how to use these commands myself, not just grab a script off the shelf, so I appreciate you breaking it down for me so I can see what's what.

You're welcome! I can understand that. Myself, I'd never even think of using a script without understanding it, and often tweak it, because a script is an over-powerfull tool, that can do much damage if not used as it was intended to be.

 

Yves.

Link to comment
Share on other sites

Not done yet by any means, but with the advantage of knowing some particulars of the file and the strings needed, I was able to come up with this, which takes us up to line [5] in your script.

 

grep '^  Option' /etc/X11/xorg.conf | egrep -v Device\|Protocol\|SHMConfig | sed 's/[ ]\+Option[\t]\+"\([A-Za-z]\+\)"[\t]\+"\([0-9\.]\+\)"/=\1=\2/'

# one line, I'm just shooting off commands in console so far...

 

The Option lines I need to read were copied out of the driver's README file so their line-start spacing is unique in the file (handy!) - so as long as any additions I make also start with two spaces and use tabs inbetween, it remains effective.

 

After that point - and I'll stress that I'm still not aware enough to be certain - I think you diverged from the spec. The thing is, the offending values that need to be corrected, _are_ already defined in the output, but defined wrong. So the next job, in effect, is to identify options that are in the synclient output, but whose values don't match the ones we've retrieved from the file.

 

I'm sorry if I misunderstand what the final parts of the code is doing, I'm not certain at all, and I'm grateful for your help.

 

We can use grep and sed again to construct a stream with the same format as the one we've produced from the file, so the last parts should be,

 

1) For each line in the XF86Config stream, search for the matching option in the synclient stream. If [a] it's there and the value is different, output it.

 

2) Take the output from (1) and execute 'synclient <line>' for each line.

Link to comment
Share on other sites

**POSSIBLE COP-OUT APPROACHING**

 

Something occurred to me about the last part of the task. What I proposed in the last post is gonna require a few more pipes, a fair bit of looping, and goodness knows what else. Soooo...

 

What if I just have synclient run _all_ the configs generated by the earlier steps?

 

I'd still know if any newly-added configs were malformed because synclient would puke, and the commands run really quick so I know it's not taxing the system too much. Seems like a better option in practical terms, though it'd still be interesting to bear out the original method to see how it could be done.

 

I'd still like to see some kind of output on the operation, to show what was changed. Maybe if I store the original synclient output before starting, then repeat afterwards, and do some type of 'diff' on the two outputs.

 

Just thinking aloud really - what do you think, Yves? Would completing the script in the originally intended manner be a major resource-eater?

Link to comment
Share on other sites

1) For each line in the XF86Config stream, search for the matching option in the synclient stream. If [a] it's there and the value is different, output it.

2) Take the output from (1) and execute 'synclient <line>' for each line.

Unless there's something I don't understand, that's exactly what lines [6] to [9] do... I'll try and explain a bit more, based on the formerly linked-to post you wrote.

 

synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=.*$/=\1=/p'

should give:

=LeftEdge=
=RightEdge=
=TopEdge=
=BottomEdge=
=FingerLow=
=FingerHigh=
=MaxTapTime=
...and so on.

synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=[[:blank:]]*\([^[:blank:]]*\)[[:blank:]]*$/\1=\2/p'

should give:

LeftEdge=120
RightEdge=830
TopEdge=120
BottomEdge=650
FingerLow=14
FingerHigh=15
MaxTapTime=0
...and so on.

 

Now under each step, I'll write what I expect to be the result:

[1]sed -n '
[2]  /^[[:blank:]]*Driver[[:blank:]]*"synaptics"[[:blank:]]*$/,/^[[:blank:]]*EndSection[[:blank:]]*$/ {
[3]    s/^[[:blank:]]*Option[[:blank:]]*"\([^="]*\)"[[:blank:]]*"\([^"]*\)"[[:blank:]]*$/=\1=\2/p
[4]  }
[5]' /etc/X11/XF86Config \

=Device=/dev/psaux
=Protocol=auto-dev
=SHMConfig=1
=LeftEdge=120
=RightEdge=830
=TopEdge=120
=BottomEdge=650
=FingerLow=14
=FingerHigh=15
=MaxTapTime=150
=MaxTapMove=110
=MaxDoubleTapTime=400
=ClickTime=30
=EmulateMidButtonTime=75
=VertScrollDelta=20
=HorizScrollDelta=20
=MinSpeed=0.3
=MaxSpeed=0.75
=AccelFactor=0.015
=EdgeMotionMinSpeed=2
=EdgeMotionMaxSpeed=4
=UpDownScrolling=1

[6]| grep -Ff <(synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=.*$/=\1=/p') \

=LeftEdge=120
=RightEdge=830
=TopEdge=120
=BottomEdge=650
=FingerLow=14
=FingerHigh=15
=MaxTapTime=150
=MaxTapMove=110
=MaxDoubleTapTime=400
=ClickTime=30
=EmulateMidButtonTime=75
=VertScrollDelta=20
=HorizScrollDelta=20
=MinSpeed=0.3
=MaxSpeed=0.75
=AccelFactor=0.015
=EdgeMotionMinSpeed=2
=EdgeMotionMaxSpeed=4
=UpDownScrolling=1

[7]| sed 's/^=//' \

LeftEdge=120
RightEdge=830
TopEdge=120
BottomEdge=650
FingerLow=14
FingerHigh=15
MaxTapTime=150
MaxTapMove=110
MaxDoubleTapTime=400
ClickTime=30
EmulateMidButtonTime=75
VertScrollDelta=20
HorizScrollDelta=20
MinSpeed=0.3
MaxSpeed=0.75
AccelFactor=0.015
EdgeMotionMinSpeed=2
EdgeMotionMaxSpeed=4
UpDownScrolling=1

[8]| grep -vFxf <(synclient -l | sed -n 's/^[[:blank:]]*\([^[:blank:]=]*\)[[:blank:]]*=[[:blank:]]*\([^[:blank:]]*\)[[:blank:]]*$/\1=\2/p') \

MaxTapTime=150
MaxDoubleTapTime=400
ClickTime=30
HorizScrollDelta=20
EdgeMotionMinSpeed=2
EdgeMotionMaxSpeed=4

[9]| while read cmd; do eval synclient "'${cmd}'"; done

execute:
synclient 'MaxTapTime=150'
synclient 'MaxDoubleTapTime=400'
synclient 'ClickTime=30'
synclient 'HorizScrollDelta=20'
synclient 'EdgeMotionMinSpeed=2'
synclient 'EdgeMotionMaxSpeed=4'

 

Is that what you expect? Maybe there's something I did not understand correctly...

 

Yves.

Link to comment
Share on other sites

:oops: I really should have studied your script more carefully! :oops:

 

 

My misapprehension came from the wording of your explanation, more than the code (which I hadn't understood yet). Thanks for bearing with a fool!

 

I'll run it and see how it goes, like I should have in the first place!

Link to comment
Share on other sites

... You make me feel embarassed :lol: ...

Never trust anyone's code (not even mine) until you at least understand the general working of it. That's not because we're bad people :) but because we can all make mistakes (especially when no test is possible), and a little misunderstanding may lead to a script that does something absolutely different from what you intended, and possibly devastating...

 

It's nice that you learn and understand what others suggest :)

 

Yves.

Link to comment
Share on other sites

Cool, I - sorry, we - have finally done it!

 

#!/bin/bash

echo Correcting all synaptics settings...
grep '^  Option' /etc/X11/xorg.conf | egrep -v Device\|Protocol\|SHMConfig | sed 's/[ ]\+Option[\t]\+"\([A-Za-z]\+\)"[\t]\+"\([0-9\.]\+\)"/\1=\2/' | grep -vFxf <(synclient -l | sed -n 's/^[ ]\+\([A-Za-z]\+\)[ ]\+=[ ]\+\([0-9\.]\+\)[ ]*$/\1=\2/p') | while read cmd; do
(eval synclient "${cmd}" || echo Couldn\'t add value "${cmd}") && echo Bullied value "${cmd}";
done
echo Done.

 

Yves, this is I think essentially what you provided to begin with, just boiled down a little (alphanumerics for the options, floats for the values, and spaces/tabs for blanks because I have the luxury of knowing which goes where :) ) and with a bit of error-trapping added.

 

I wondered for a long time why it puked with syntax-errors when I ran it in console, it has something to do with Bash bersus sh it seems, so I made it explicitly a Bash script (funny, I always thought it was the same thing on Mandrake!)

 

Anyway, this baby is going in my KDE Autostart folder - I guess it could go somewhere in the init system after X starting, but this is just easier for me since I only use KDE.

 

Every time I posted in this thread I thanked Yves, and this is no exception dammit! I think this is the most important forum on this board for committed Linux learners, and sir you do it proud. Thank you!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...