The macosxhints Forums

The macosxhints Forums (http://hintsforums.macworld.com/index.php)
-   UNIX - General (http://hintsforums.macworld.com/forumdisplay.php?f=16)
-   -   Global variables in shell scripts (http://hintsforums.macworld.com/showthread.php?t=110127)

tlarkin 03-16-2010 09:59 AM

Global variables in shell scripts
 
I am not sure how to word this. Let's say I write a lot of shell scripts for my Macs at work and I want to set up an array of global variables that any script can call, outside of the script. Eample:

$1 = current user

$2 = name of start up volume

$3 = computer name

$4 = current IP address of the NIC


You get the point? How would one go about accomplishing such a thing? Run all scripts through a framework?

#Edit#

I guess I could maybe alter the profiles for every user for bash and set functions and aliases and variables in the bash profile and then whenever that user runs a script, they could call those variables....

hayne 03-16-2010 10:07 AM

The easiest (and probably best) way is to define those variables in a script that is then 'source'd by the other scripts.

globalVariables.sh
Code:

#!/bin/bash
currUser=$USER
startupVolume="Macintosh HD"
computerName="Fred's Mac"
currIpAddr=`getCurrentIpAddress.sh`

otherScript.sh
Code:

#!/bin/bash
source /path/to/my/scripts/globalVars.sh

echo "Computer name is $computerName"


tlarkin 03-16-2010 10:09 AM

Hayne,

As always you are right on the money. My top google hits pretty much returned what you posted. Thanks as always.

SirDice 03-16-2010 10:13 AM

Don't use bash for such simple tasks. Use the 'standard' bourne shell (/bin/sh).

Current user is already defined with $USER. So is the computername; $HOST.

tlarkin 03-16-2010 10:19 AM

Quote:

Originally Posted by SirDice (Post 576171)
Don't use bash for such simple tasks. Use the 'standard' bourne shell (/bin/sh).

Current user is already defined with $USER. So is the computername; $HOST.

I always use bash, as it is the default shell and has all functionality of shell. If you can please explain to me why I should use shell over bash I'd be glad to hear it.

Also, sometimes a script will run as root, so I need to figure out what the current user is. My method is seeing who currently owns the console, since the currently logged in user should always own the console.

Code:

ls -l /dev/console | awk '{ print $3 }'
This will return the current user, if I just use $USER it will return root if my script is running as root.

hayne 03-16-2010 10:26 AM

Quote:

Originally Posted by SirDice (Post 576171)
Don't use bash for such simple tasks. Use the 'standard' bourne shell (/bin/sh).

I'd be interested to hear more about why you recommend that.
(I'm assuming that the scripts are for OS X only, so availability of 'bash' (e.g. on older hardware) is not an issue.)

By the way, note that on OS X, 'sh' is just 'bash' invoked under another name.

SirDice 03-16-2010 10:27 AM

Quote:

Originally Posted by tlarkin (Post 576173)
I always use bash, as it is the default shell and has all functionality of shell. If you can please explain to me why I should use shell over bash I'd be glad to hear it.

Bash is slow compared to sh. Also /bin/sh is a POSIX shell. If you write a script in bourne shell it will run on pretty much every *nix flavor under the sun.

Quote:

Also, sometimes a script will run as root, so I need to figure out what the current user is.
That will be root, as the script runs as root.

There's no notion of "current user". Unix is a multi-user system and so is OS-X. There can be multiple users logged in at the same time.

hayne 03-16-2010 10:30 AM

Quote:

Originally Posted by SirDice (Post 576177)
Bash is slow compared to sh

I'd be very interested to see some numbers showing this (on OS X).
See my comment above about 'bash' and 'sh' being essentially the same program on OS X.

Quote:

There's no notion of "current user". Unix is a multi-user system and so is OS-X. There can be multiple users logged in at the same time.
But there is still only one user who has access to the graphical facilities of OS X - the user who is sitting in front of the Mac.

SirDice 03-16-2010 10:45 AM

Quote:

Originally Posted by hayne (Post 576178)
See my comment above about 'bash' and 'sh' being essentially the same program on OS X.

On Linux it is. /bin/sh is actually hardlinked to /bin/bash. On *BSD it certainly isn't. Not sure about OS-X though.

Still, I would use the bourne syntax. I've seen to many scripts riddled with bashisms that people try to run on systems that only have the 'regular' bourne shell.

It's easier to learn new things then it is to unlearn bad habbits :D

hayne 03-16-2010 10:50 AM

Quote:

Originally Posted by SirDice (Post 576179)
Still, I would use the bourne syntax. I've seen to many scripts riddled with bashisms that people try to run on systems that only have the 'regular' bourne shell.

I used to agree.
But nowadays I don't think there are many people who care about any Unix system other than OS X and Linux.

tlarkin 03-16-2010 10:57 AM

I have BSD 8, Ubuntu 9, Fedora 10, OS X, and open SuSe at home. All of them by default use /bin/bash as the default shell. I just recently bought a few books on bash, and the books all tell me, that bash has full functionality of shell, and in most cases works both ways. With some exceptions where bash is more functional than bourne shell.

I looked around, and the only other shell I can see that is close to being as widely used as bash seems to be korn. I don't know all the differences of the shell because I haven't extensively used them all. In the current O'Reilly book I am reading, which is all about bash 3.0. The first chapter states that bash takes all the good things from c shell, korn, and bourne shell, and combines them with other robust features to create bash.

Also, there are many global variables I could use while scripting. If I want to invoke say the defaults write command on a script to modify a property list, I need to do so as the user, not as root, because that will just modify the root user. So, I could hard code these global variables to get a list of all user accounts, and then loop it to modify that plist. That is just one small tiny example.

Not to mention, this is my enterprise, these are my organizations systems with the image I created. So, setting up a series of global variables may be very beneficial for me from a systems management view. Also, everything is standard, so I know what is going on and I know by default every shell is set to bash.

Thanks for your time guys, it is always appreciated.

SirDice 03-16-2010 11:00 AM

Quote:

Originally Posted by tlarkin (Post 576181)
I have BSD 8, Ubuntu 9, Fedora 10, OS X, and open SuSe at home. All of them by default use /bin/bash as the default shell.

FreeBSD does NOT and never has bash as the default shell. It's not even part of the base OS.

Quote:

I looked around, and the only other shell I can see that is close to being as widely used as bash seems to be korn.
Look more closely. All startup (init) scripts on AIX, Solaris, HP-UX, BSD and quite a few others use the bourne shell (that's /bin/sh) not bash.

SirDice 03-16-2010 11:10 AM

Quote:

Originally Posted by hayne (Post 576180)
But nowadays I don't think there are many people who care about any Unix system other than OS X and Linux.

Great, this means more work for me as I can work with AIX, HP-UX, Solaris and *BSD. It also means I can increase my rates :D

Hal Itosis 03-17-2010 12:56 AM

Quote:

Originally Posted by SirDice (Post 576179)
On Linux it is. /bin/sh is actually hardlinked to /bin/bash.

That alone tells us all we need to know: for Linux bash is the shell of choice... and that hard link:
  1. saves folks the trouble of having to change (rewrite/save) every silly script that has #!/bin/sh into #!/bin/bash

    Remember: bash is designed to be fully backwards compatible and able to run any sh script, but sh OTOH does not make that claim (about bash). Essentially, bash replaces sh... not vice versa.

  2. forces every script that even tries to run sh to actually call bash.

So the notion that folks 'should' prefer sh is false... or, only true if we want our scripts to run on machines which have no bash binary. (safe to say: Mac users need not have that care).

sh is an ancient relic too old to be concerned about, and bash offers too many improvements to ignore.

SirDice 03-17-2010 05:45 AM

Quote:

Originally Posted by Hal Itosis (Post 576260)
sh is an ancient relic too old to be concerned about,

It's just as old as Unix. Maybe we should forget about that too?

And you're completely missing the point. But that seems to happen a lot on this board :rolleyes:

acme.mail.order 03-17-2010 06:39 AM

Quote:

Originally Posted by SirDice (Post 576278)
And you're completely missing the point. But that seems to happen a lot on this board :rolleyes:

No, we get your point - some people disagree.


Quote:

Originally Posted by SirDice (Post 576177)
Bash is slow compared to sh. Also /bin/sh is a POSIX shell. If you write a script in bourne shell it will run on pretty much every *nix flavor under the sun.

Got some benchmarks to support this? Speed of a simple shell script on a multi-gigahertz machine really isn't a big issue anymore. If sh runs my script 0.0003 sec faster than bash I probably won't notice, and I'm definitely not boning up on another language for it.

I write ~80% of my maintenance scripts in PHP anyway.

Quote:

Originally Posted by SirDice (Post 576177)
There's no notion of "current user". Unix is a multi-user system and so is OS-X. There can be multiple users logged in at the same time.

Sure can be, but only one has the Desktop, and only one will be listed in /dev/console

Quote:

Originally Posted by hayne (Post 576176)
(I'm assuming that the scripts are for OS X only, so availability of 'bash' (e.g. on older hardware) is not an issue.)

By the way, note that on OS X, 'sh' is just 'bash' invoked under another name.

What Hayne said. In Leopard, /bin/sh and /bin/bash are nearly identical in size (32 bytes difference) so it really smells like the same codebase.

Quote:

Originally Posted by SirDice (Post 576182)
FreeBSD does NOT and never has bash as the default shell. It's not even part of the base OS.

Sounds like someone needs to update their base OS. I see that as a defect, not a feature.

Quote:

Originally Posted by SirDice (Post 576182)
Look more closely. All startup (init) scripts on AIX, Solaris, HP-UX, BSD and quite a few others use the bourne shell (that's /bin/sh) not bash.

Which tells me they were written (and re-written) by people more familiar with sh. Or the script is a legacy item from the days when sh did things better.

The original question was for OSX scripts, and bash is omnipresent, so no problem.

SirDice 03-17-2010 06:57 AM

Quote:

Originally Posted by acme.mail.order (Post 576284)
No, we get your point - some people disagree.

Fair enough.

Quote:

Got some benchmarks to support this? Speed of a simple shell script on a multi-gigahertz machine really isn't a big issue anymore. If sh runs my script 0.0003 sec faster than bash I probably won't notice, and I'm definitely not boning up on another language for it.
I look for it. Don't have one handy. But I do know the differences are a lot more significant then that.

Quote:

Sure can be, but only one has the Desktop, and only one will be listed in /dev/console
True. But the naming "current user" isn't correct and can lead to misunderstandings.

Quote:

What Hayne said. In Leopard, /bin/sh and /bin/bash are nearly identical in size (32 bytes difference) so it really smells like the same codebase.
Then I'm wondering why they didn't take the linux route and just symling /bin/sh to /bin/bash. One codebase instead of two.

Quote:

Sounds like someone needs to update their base OS. I see that as a defect, not a feature.
Why? It works perfectly fine with the bourne shell. For interactive use we have (t)csh. And if you really must you can always install korn, bash, zsh and quite a few others as a port. Why clutter up the base? Also bash is GPL and thus cannot be added to the base (BSD Licensed).

Quote:

Which tells me they were written (and re-written) by people more familiar with sh. Or the script is a legacy item from the days when sh did things better.
Init scripts have been around for as long as Unix has been around. Those scripts aren't going to be re-written in another shell.

Quote:

The original question was for OSX scripts, and bash is omnipresent, so no problem.
Hey, it's your system. I just think learning bourne will benefit you more. Maybe it's because I use and maintain more different flavors of *nix.

Hal Itosis 03-17-2010 11:36 PM

Quote:

Originally Posted by SirDice (Post 576278)
It's just as old as Unix. Maybe we should forget about that too?

Bash is an excellent replacement for sh, because that was the precise purpose of its design. If you know about something that replaces all of "Unix" with as much precision and inherent *backwards* compatibility -- please share.


Quote:

Originally Posted by SirDice (Post 576278)
And you're completely missing the point. But that seems to happen a lot on this board :rolleyes:

Perhaps because this is a Mac OSX-oriented board, and thus caters to an audience to which your "point" was less significant.

;)

Seriously though: over the years, Bash has borrowed little bits here and there from zsh (and Perl?), and those enhancements are becoming (have become?) the 'norm' now. Bash *is* the new sh. I don't think anyone here is worried about running their scripts on a PDP-11.

:D

Hal Itosis 03-18-2010 05:58 PM

Sorry i didn't catch this last night (perhaps since it's part of a reply to someone else, i just skipped it before):

Quote:

Originally Posted by SirDice (Post 576286)
I just think learning bourne will benefit you more.

Learning sh more beneficial than learning Bash? :confused:

Two things about that...
  • Bash is an extension of sh -- or viewed from another angle, sh is a subset of bash. Learning bash is learning sh... plus a few enhancements.

  • i count a total of 15 instances of the string “bourne” so far, and not one of them has been capitalized (to honor Steve Bourne).
Good Sir Dice, may i suggest it's not too late to be Bourne again. :)

tlarkin 03-18-2010 08:25 PM

well back on topic....

So, when I set up my commands, and then source it, it does not seem to be working. What is the best method? Can I literally just put 1=`some commands` and then echo $1 or call for $1 in a script sourced to my global variables?

Thanks

So for example, I am looking at using functions, but not sure how to output them to numbered variables...

Code:

#!/bin/bash

# get current logged in user

function currentuser {

CurrentUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'` 1>&2

CurrentUser="1"

1="currentuser"

/bin/echo "$1"

}

I just can't quite wrap my head to output that code so that it equals $1, and then when I source it in a script I can just use $1 and it will always pull the currently logged in user.

hayne 03-18-2010 08:38 PM

Quote:

Originally Posted by tlarkin (Post 576515)
So, when I set up my commands, and then source it, it does not seem to be working.

As usual when asking about a problem, you need to supply details of what happens and why this is not what you want.

Quote:

Can I literally just put 1=`some commands` and then echo $1 or call for $1 in a script sourced to my global variables?
I don't think "1" is an allowable variable name. $1, $2, etc are special variables that get set to the command-line arguments of a script.

tlarkin 03-18-2010 09:12 PM

Well, certain things get parsed at log in with hard coded variables in OS X, so when a script runs as a log in hook, $1 is always something, $2 is always something, so I was assuming that login hooks sourced some commands which output the desired result to $1.

So, in my case, if I sourced my global variables, and say the currently logged in user is output to $1 I could do this in a script

defaults write /Users/$1/Library/Preferences/com.mycompany "some_options" -bool true

I think I want to build functions, but just not sure how to set them to certain variables. I know some third party stuff also uses $1, $2, $3 at log in to utilize certain hard coded variables.

Sorry if I am not making much sense

hayne 03-18-2010 09:52 PM

Third party stuff does not set $1, $2, etc to values - as I said before, those values come from the command-line args used when the script was invoked.

I'm not sure what you are missing - i.e. why the sort of example (with suggested variable names) I gave above is not what you want.

tlarkin 03-18-2010 10:05 PM

Quote:

Originally Posted by hayne (Post 576534)
Third party stuff does not set $1, $2, etc to values - as I said before, those values come from the command-line args used when the script was invoked.

I'm not sure what you are missing - i.e. why the sort of example (with suggested variable names) I gave above is not what you want.

Well, in the specific example I gave, parameters do get passed to $1, $2, and $3 by third party framework, but only at login. I assume that is because they modified the existing Apple stuff when running scripts as log in hooks.

I guess, I don't have to output it to a number, but I was thinking it may be easiest that way.

Thanks

hayne 03-18-2010 10:18 PM

Quote:

Originally Posted by tlarkin (Post 576537)
Well, in the specific example I gave, parameters do get passed to $1, $2, and $3 by third party framework

Your use of the word "framework" makes me think that you are talking about shell scripts invoked from a compiled program (e.g. one written in C). In that case, the compiled program specifies what command-line arguments it wants the shell script to receive. And then Bash sets $1, $2, etc to those command-line arguments.

tlarkin 03-18-2010 10:52 PM

Quote:

Originally Posted by hayne (Post 576538)
Your use of the word "framework" makes me think that you are talking about shell scripts invoked from a compiled program (e.g. one written in C). In that case, the compiled program specifies what command-line arguments it wants the shell script to receive. And then Bash sets $1, $2, etc to those command-line arguments.

That very well could be what it is

Hal Itosis 03-19-2010 02:55 AM

Quote:

Originally Posted by tlarkin (Post 576515)
well back on topic....

So, when I set up my commands, and then source it, it does not seem to be working. What is the best method? Can I literally just put 1=`some commands` and then echo $1 or call for $1 in a script sourced to my global variables?

Thanks

It sure seemed that post#2 (hayne) covered it pretty well. Observe how "numbers" (positional parameters) are not connected to "global variables" through any special relationship.

From post #2:
Quote:

otherScript.sh

Code:
#!/bin/bash
source /path/to/my/scripts/globalVars.sh
echo "Computer name is $computerName"
Note how otherScript.sh echos some variable called "computerName" seemingly out of nowhere? It didn't declare or initialize it anywhere. Where did it come from? Did you test out his two files to understand how they work?


Quote:

Originally Posted by tlarkin (Post 576515)
So for example, I am looking at using functions, but not sure how to output them to numbered variables...

<snip>

I just can't quite wrap my head to output that code so that it equals $1, and then when I source it in a script I can just use $1 and it will always pull the currently logged in user.

If you want "numbered" variables, i'll show you how it can be done (but usually there are reasons for doing this... which probably don't apply here). Note: in bash, a period '.' (as a command) is the same as the "source" builtin...

# SHELL SCRIPT:
$ cat foo
Code:


#!/bin/bash -
IFS=$' \t\n'
declare -x PATH=/bin:/usr/bin

. ~/.myConfigs

echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo
echo "computer name    = $computerName"
echo "ethernet address = $etherAddress"
echo "boot disk name  = $bootDiskName"
echo
sleep 2

# assigning items to the positional parameters:
set -- "$computerName" "$etherAddress" "$bootDiskName"

# ^ REPLACES whatever positional parameters previously existed.
# Is that what you want?

echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"

exit $?

Note how (like hayne's post #2 example) that foo prints out 3 variables without ever declaring or initializing them. Here's the hidden config file it sources to get the data...

# CONFIG FILE:
$ cat .myConfigs
Code:


computerName=`/bin/hostname -s`
etherAddress=`/sbin/ifconfig en0 ether |/usr/bin/sed '2!d;s/^[^0]*//;s/[: ]//g'`
bootDiskName=$(/usr/sbin/diskutil info `/usr/sbin/bless --getBoot` |
/usr/bin/sed '/^ *Volume Name: */!d;s###')

. . .

And, here is what it looks like when it's run:
Code:


$ foo
$0 = /Users/halito/bin/foo
$1 =
$2 =
$3 =

computer name    = PowerBookG4
ethernet address = 000d93abcde0
boot disk name  = Hals_Mac

$0 = /Users/halito/bin/foo
$1 = PowerBookG4
$2 = 000d93abcde0
$3 = Hals_Mac

Try it out, and then decide. [i don't think reassigning the number variables offers any advantage here.]

BTW...
Quote:

>> So for example, I am looking at using functions
Functions also get assigned their own positional parameters (arg list), so that adds even more to the potential confusion. The body of a script gets its numbered variables and functions get whatever args we call them with.

tlarkin 03-19-2010 02:04 PM

I was thinking I could pass a bunch of arguments to a function and then just call that function in a script. I could, case things for different OS versions and what not. Though, this is getting slightly above my skill level, but I am willing to learn.

I just think numbers would be easier than word variables, but then again as long as I am writing everything I can kind of do it how I want. I was thinking more along the lines of setting this up, so when other people in my department need to write a script they can call global variables for simple one liners instead of hashing everything out.

Thanks

Hal Itosis 03-19-2010 02:27 PM

Still using my foo script from post #27, perhaps this run (including some args on the command line this time) will better illustrate what's happening:
Code:

$ foo these are arguments
$0 = /Users/halito/bin/foo
$1 = these
$2 = are
$3 = arguments

computer name    = PowerBookG4
ethernet address = 000d93abcde0
boot disk name  = Hals_Mac

$0 = /Users/halito/bin/foo
$1 = PowerBookG4
$2 = 000d93abcde0
$3 = Hals_Mac



All times are GMT -5. The time now is 05:51 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.