LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   bash - setting a persistent variable that remains after the script exits (http://www.linuxquestions.org/questions/programming-9/bash-setting-a-persistent-variable-that-remains-after-the-script-exits-699591/)

CJ Chitwood 01-24-2009 10:35 AM

bash - setting a persistent variable that remains after the script exits
 
Hello to the group...

I've got a Sony Vaio VGN NR-160E (Sony M/N PCG-7Z1L) laptop. I recently discovered through searches that I can control the backlight with a little program called "xbacklight". However, it requires that on first run a program called "xrandr" is run. This is no big deal. Just write a short, simple little diddy that runs xrandr first, then xbacklight with the first command-line variable as the brightness. No big deal.


The problem is that xrandr blanks the screen momentarily. It's quite distracting, though harmless as far as I can tell. Since xrandr is only required to have been run once at any time since boot before the brightness is set, and it stays resident so it's not needed again, I want only to run xrandr the very first time this script is run from reboot.

I could make entries for startup scripts, but I'd like to make a script that I can upload and say "get these two programs and run this script" regardless of distro, and I can't do that if I have to say "oh, and you need to make this change to your startup scripts". I want it easy for the other people. (I'm doing this as a tiny little way to start giving back to the FOSS community, though I realize it's not much.)


So, I have this script pretty much written, except for one tiny little thing. I can't tell if xrandr has already run or not.

My question then is this:

How can I set a variable in a shell script that will persist in the environment outside of the script so that if the script completes and is run again later the variable is still present in the new execution?

I can set the var with no problem and check it and everything else within the script, but say I have pseudocode something like this:

Code:

Begin-------------------
Check if variable exists.  Does it?
--Yes
----Echo "Variable exists...  moving on..."
----Call "set-backlight"
--No
----Set variable to some value (arbitrary)
----Echo "xrandr hasn't run yet;  running xrandr..."
----Run xrandr
----Call "set-backlight"

set-backlight()
{
  Echo "Setting backlight brightness as requested..."
  Run xbacklight with appropriate arguments
  return
}

End---------------------

It's the "check if variable exists" option that gets me.

Now, I've found some references in one of the usenet groups by a couple of gents named "Bit Twister" and "Chris F. A. Johnson" (though I don't remember which newsgroup it was) that referenced a bunch of ways of testing variables in bash, and they all work, except that if I exit the script and come back to it, the variables no longer exist. I've tested this with

Code:

Begin-------------------

Check if variable exists
--Yes
----Echo "Variable exists"
----Exit
--No
----Echo "Variable Does not exist.  Setting now."
----Set variable to whatever

Check if variable exists
--Yes
----Echo "Variable was successfully set"
----Exit
--No (never runs)
----Echo "Variable was NOT set..."

End---------------------

and gotten predictable and expected results.

I just want to set the variable in one script, and either in a second running of that same script or even from another script be able to see that same variable with the same setting.


Any help, please?

bgeddy 01-24-2009 11:59 AM

Well - as the script runs it own instance of bash variables are lost when the script exits variables are lost. You could "source" a script so it's commands are ran in the user's bash session or have a disk based flag file to indicate the run status. Another option is to have a self modifying bash script. I have written a litte example here:
Code:

#!/bin/bash
if [  -n "$1"  ];then
      if  [ "$1" = "-F" ]; then
                if [ "$(tail -n1 $0)" = "#END" ]; then
                        echo "Clearing END indicator"
                        sed -i '$d' $0
                        exit 0
                else
                        echo "Error - no end indicator to clear"
                        exit 1
                fi
        else
                echo "Useage $0 [-F] .. -F forces the prior run indicator to be cleared"
                exit 1
        fi
fi
if [ "$(tail -n1 $0)" = "#END" ];then
        echo "We've been ran before"
else
        echo "First time run"
        echo "#END" >> $0
fi
exit 0

You could incorporate this system into your script. It checks to see if it's been ran before by looking for a flag "#END" as the last line. If it's not there it adds it and does some stuff. This may be cleared by running the script with "-F" parameter. You could clear this flag on shutdown with rc.shutdown or such like and run the script on startup from rc.local or some such way.

CJ Chitwood 01-24-2009 12:06 PM

Thank you.

I'm trying to avoid having to put anything in the startup/shutdown scripts, but it's looking more like I'll have to write some kind of C code or something to accomplish that. Startup/shutdown edits may be the only easy way to do it...


I was thinking about it some more, though... If xbacklight only works after xrandr is set, what does xrandr set in the system that makes xbacklight work? Why not just look for that item and if it doesn't exist, then run xrandr? That would work... I just have to find out what xrandr does so I know what to look for... :shrugs:

Thanks, and I'll keep your suggestion in mind.

pcunix 01-24-2009 12:31 PM

Quote:

Originally Posted by CJ Chitwood (Post 3419835)
Thank you.

I'm trying to avoid having to put anything in the startup/shutdown scripts, but it's looking more like I'll have to write some kind of C code or something to accomplish that. Startup/shutdown edits may be the only easy way to do it...


An "ls -lut" of xandr will tell you when something last used it.. you could compare that you your login time from "last" and run it again if needed.

PTrenholme 01-24-2009 12:49 PM

From your description, xrandr sounds like a X rendering "add-on" which may be running as a separate process. Try a ps -e | grep xrandr to see if there's a process by that name running. If there is, then all you need in your script is

[ -z "$(ps -e | grep xrandr)" ] && xrandr

to start it if it's not running.

(I'd check myself, but I'm stuck on Vista right now. I've started a big download that I don't want to interrupt.)

CJ Chitwood 01-24-2009 02:59 PM

Quote:

Originally Posted by pcunix (Post 3419864)
An "ls -lut" of xandr will tell you when something last used it.. you could compare that you your login time from "last" and run it again if needed.

Good idea -- this is quite acceptable. Instead of login time, though, I'm thinking of using the time "gdm" or some similarly used-every-login program is run because it would be easier to directly compare times (really, not much different, since with "last" I'd simply have to add a grep for "still" (still logged in), but at least comparing the output of "ls" to "ls" will use the same "cut" command as opposed to comparing "ls" to "last").

The only problem then would be with logging in before midnight and running the program both before and after midnight, but this is an extremely unlikely scenario and running xrandr a second time per login really isn't anything major.

I'm going to run with this and see what I can get... Thanks!


Still open to other suggestions though!

CJ Chitwood 01-24-2009 03:01 PM

Quote:

Originally Posted by PTrenholme (Post 3419895)
From your description, xrandr sounds like a X rendering "add-on" which may be running as a separate process. Try a ps -e | grep xrandr to see if there's a process by that name running. If there is, then all you need in your script is

[ -z "$(ps -e | grep xrandr)" ] && xrandr

to start it if it's not running.

(I'd check myself, but I'm stuck on Vista right now. I've started a big download that I don't want to interrupt.)

Hmm... Well, this still runs xrandr every time... I must have been wrong -- the xrandr is not running resident, so I don't know what it's doing that allows xbacklight to work only after it has run. Whatever it is, when I find it, I'll have a guaranteed "will it work" qualifier....

I will strace it sometime tonight when I get back to the computers to see if it's writing to a file or something...

Thanks though... All else fails, I'll run with the time-stamp idea above...

PTrenholme 01-24-2009 07:31 PM

:scratch: Well, I finished the download, and -- now back on Fedora -- I looked at man xrandr and discovered that it was just a interface to RandR, not a daemon that would keep running. If it's called with no arguments, all it does is report the current rendering state of screen :0
Code:

$ xrandr
Screen 0: minimum 320 x 240, current 1440 x 900, maximum 1440 x 900
default connected 1440x900+0+0 0mm x 0mm
  1440x900      50.0*
  1024x768      51.0
  800x600        52.0    53.0
  640x512        54.0
  640x480        55.0    56.0
  512x384        57.0
  400x300        58.0
  320x240        59.0

This implies to me that when you said
Quote:

However, it requires that on first run a program called "xrandr" is run.
in your first post, you neglected to mention the arguments used when you invoked the program.

In any case, look at man xrandr to see how you can use the command to report the current state of whatever setting you were changing in the first call, and write your script so it only changes the setting when it doesn't have the desired value.

CJ Chitwood 01-24-2009 07:40 PM

yes, that's what I was thinking at 3:00 when I posted last... Xrandr is setting something, somewhere, so all I need to do is find it. However, the strace I just ran was less than helpful (maybe I just don't know enough about strace yet).

So, I think now I'll read up on XRandR and get info on what exactly it's changing... or you're right, I should just check the output of xrandr by itself and see what is changed!

And sorry, I didn't realize I would need the arguments to xrandr in the post, but I see they may have helped much earlier on...

Thanks!

CJ Chitwood 01-24-2009 08:48 PM

GOT IT! Thanks to all for the help!

I run debian, and the following are installed. I really don't think I need the -dev package installed, but I list it just in case...

libxrandr2
libxrandr-dev
xbacklight


There should be similar packages available for other distros.


My script is as follows


Code:

#!/bin/bash
# by CJ Chitwood
# cj.chitwood <from> gmail.com
# with the help of linuxquestions.org
#
# http://www.linuxquestions.org/questions/programming-9/bash-setting-a-persistent-variable-that-remains-after-the-script-exits-699591/
# (and Google hits too numerous during my searches to remember)
#
# This file is not maintained.  It is provided as-is and
# may be considered free-use/public domain.
#
# requires programs "xrandr" and "xbacklight".  Edit PATH to
# point to the directories that contain these.  In Debian, this
# is /usr/bin.
##############################################################################

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; export PATH

if [ $# -ne 1 ]; then
    echo -e 1>&2 Usage: setbl [arg], where 0 \<\= [arg] \<\= 100.
    exit 127
  else
    ARG=$1;
fi

setBacklight()
{ echo Attempting to set backlight to $ARG%...
  xbacklight -set $ARG
  return
}


TEMPVAR=`xrandr --verbose | grep BACKLIGHT_CONTROL | cut -d : -f 2 | cut -d " " -f 2`

if [ $TEMPVAR == "native" ]; then
    setBacklight
    exit 0
  elif [ $TEMPVAR == "kernel" ]; then
    echo xrandr has not yet been run.  Running xrandr...
    xrandr --output LVDS --set BACKLIGHT_CONTROL native
    setBacklight
  else
    # This block of code should, in theory, never run;
    # but, since I only own a VGN-NR160E, I can't test other
    # models to be sure of this assumption.
    echo xrandr shows an unknown backlight control state...
    echo The current output of "xrandr --verbose | grep BACKLIGHT_CONTROL" is:
    echo    $TEMPVAR
    echo and since I expect either "native" or "kernel", I don\'t know what
    echo to do with it...
    echo I wonder if you\'re running me on a Sony Vaio VGN NR-series...
    echo Not continuing, since state is unknown.  Try manual controls... 
fi

exit 0



All times are GMT -5. The time now is 10:06 PM.