Postinstall scripts and bash functions

bpavlov
Honored Contributor

I've been trying to repackage an installerI was trying to cut down on some code on a post install script by utilizing functions. When I try to run the installer command and target $3, it's not actually targeting /. Rather it is an empty value which means the installer never launches. However, if I run the same installer command outside of a function, it targets $3 and correctly installs to /.

If I run the script with bash set x, I can see the following line in console when using the installer command targeting $3 in a function:

/usr/sbin/installer -dumplog -verbose -pkg '/Volumes/path/to/installer.pkg' -target '' -allowUntrusted

Outside of a function, installer command targeting $3 results in:

/usr/sbin/installer -dumplog -verbose -pkg '/Volumes/path/to/installer.pkg' -target / -allowUntrusted

If I use the installer command and target / instead of $3, the command will also work within a function, but I know that's not the proper way to do things.

It's been a long day and this is probably an easy one. I'm guessing it has to do with certain variables not being passed to a bash function. What am I missing here?

Relevant portion of the script:

#!/bin/bash

#Working directory for script to reference resources
install_dir=`dirname $0`

# Determine OS version
osvers=$(sw_vers -productVersion | awk -F. '{print $2}')

#Variables for ScanSnap installer
ScanSnapDMG="ScanSnap.dmg"
ScanSnapDMGVolume="/Volumes/ScanSnap"
ScanSnapInstaller="ScanSnap Manager.pkg"

ScanSnap () {
    /usr/bin/hdiutil attach -nobrowse -readonly $install_dir/"$ScanSnapDMG"
    /usr/sbin/installer -dumplog -verbose -pkg "$ScanSnapDMGVolume/$ScanSnapInstaller" -target $3 -allowUntrusted
    /bin/sleep 10
    /usr/bin/hdiutil detach "$ScanSnapDMGVolume"
    /usr/bin/killall "ScanSnap Manager"
}

if [[ ${osvers} -le 7 ]]; then
    ScanSnap
fi

exit 0

EDIT: For clarification, I'm not testing in the JSS yet. I'm only testing in 10.9.5 and creating the package in Packages.

8 REPLIES 8

bentoms
Release Candidate Programs Tester

@bpavlov I think you're having an issue with JSS's Script Parameters

bpavlov
Honored Contributor

Sorry I should have clarified, I'm not testing in the JSS yet so it's not that. My only testing is in OS X 10.9.5, creating the package in Packages and running the built package.

bentoms
Release Candidate Programs Tester

@bpavlov so you're creating a PKG to locally mount a DMG to install a PKG?

Why not upload the PKG you're trying to install to Casper Admin?

Josh_S
Contributor III

Positional parameters, $0, $1, $2, $3 . . ., in bash are local variables. When you call a function, the positional parameters are defined differently in the context of that function.
http://tldp.org/LDP/abs/html/othertypesv.html

You can, outside the context of the function, define a global variable with the value of $3 in the script context. The function can then reference this variable inside the function since it is global. You can also pass the value of $3 to the function as a functional positional parameter when you call it. In this case, the position has changed and you will have to adjust your numbers accordingly. If you use the below code, it will be $1 in the context of the function.

...
if [[ ${osvers} -le 7 ]]; then
    ScanSnap "$3"
fi
...

I, personally, think the code reads better using a global variable. I try to assign variables, global or local, at the "top" of the script/function to make the code more readable and then I don't have to worry about which context I'm in.

chriscollins
Valued Contributor

Yep, what josh said. When you put $3 inside the function, that is different than the $3 that you are passing to the script.

The $3 in the function means the 3rd argument you are sending to the function.

#!/usr/bash

echo "Script argument #3:  $3"

function blah () {
        echo $3

}

blah "1" "2" "three"

and when we run it:

$ ./blah.sh 1 2 3
Script argument #3:  3
three

chriscollins
Valued Contributor
#!/bin/bash

#Working directory for script to reference resources
install_dir=`dirname $0`

# Determine OS version
osvers=$(sw_vers -productVersion | awk -F. '{print $2}')

#Variables for ScanSnap installer
ScanSnapDMG="ScanSnap.dmg"
ScanSnapDMGVolume="/Volumes/ScanSnap"
ScanSnapInstaller="ScanSnap Manager.pkg"

ScanSnap () {
    /usr/bin/hdiutil attach -nobrowse -readonly $install_dir/"$ScanSnapDMG"
    /usr/sbin/installer -dumplog -verbose -pkg "$ScanSnapDMGVolume/$ScanSnapInstaller" -target $1 -allowUntrusted
    /bin/sleep 10
    /usr/bin/hdiutil detach "$ScanSnapDMGVolume"
    /usr/bin/killall "ScanSnap Manager"
}

if [[ ${osvers} -le 7 ]]; then
    ScanSnap $3
fi

exit 0

bpavlov
Honored Contributor

Thanks @Josh_S and @chriscollins. That was very clear. The More You Know!

@bentoms I work of a simple rule. I try to do what I can so that if Casper is not available the package will work as is and has whatever logic is needed in it. From that simple rule I approach how I deploy packages. In this case this application requires 3 installers dependent on the OS version being run. I'm not going to create additional policies and/or smart groups when I can just package everything up and put the logic in a postinstall script. I chose to use the dmgs originally for just testing because I didn't want to take out the PKG out of it since it wasn't necessary and wanted to keep the original installers intact. I will ultimately take them out of the DMGs, but was just testing in this case. In certain situations I will take out the pkg if it needs to be modified right away, but in this case I didn't feel the need to do that since it was still a work in progress.

bentoms
Release Candidate Programs Tester

@bpavlov Fair do's. You have your reasons. :)