Search code examples
bashmacosshellplistplistbuddy

Path stored in plist starting with $HOME does not expand in bash script command


I am writing a bash script to automate our build process. I need to store a path in a settings plist file and retrieve it in a shell script, using plistbuddy.

The key below specifies the path where archives will be stored, a folder on the Desktop:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>archives_path</key>
   <string>$HOME/Desktop/Archives/</string>
</dict>
</plist>

In my shell script I access the key:

SETTINGS_PATH="path/to/plist/file"

ARCHIVES=$(/usr/libexec/PlistBuddy -c "Print archives_path" "$SETTINGS_PATH")
#outputs "$HOME/Desktop/Archives/"

mkdir "$ARCHIVES/test/"
#outputs "mkdir: $HOME/Desktop/Archives: No such file or directory"

The ARCHIVES var is not expanding to /Users/*username*/Desktop/Archives/, as I'd expect.

I did a test by creating a var with the same string:

ARCHIVES="$HOME/Desktop/Archives/" 

echo "$ARCHIVES" 
#expands to "/Users/*username*/Desktop/Archives/"

mkdir "$ARCHIVES/test/"
#creates the 'test' directory

As this script will be run under an unknown user account how can I force the $HOME to expand properly.


Solution

  • Your $ARCHIVE returned by the PlistBuddy contains a literal $HOME.

    Simple demo:

    str='$HOME/tmp/somefile'
    echo "The HOME isn't expanded: [[$str]]"
    

    it prints:

    The HOME isn't expanded: [[$HOME/tmp/somefile]]
    

    You can use eval for the expansion like:

    expanded_str1=$(eval "echo $str")
    echo "The HOME is DANGEROUSLY expanded using eval: [[$expanded_str1]]"
    

    which prints

    The HOME is DANGEROUSLY expanded using eval: [[/Users/jm/tmp/somefile]]
    

    But using eval is dangerous! Evaling any string which isn't absolutely under your control is really dangerous.

    So, you need manually replace the literal $HOME with it's actual value. It can be done with many ways, for example:

    expanded_str2="${str/\$HOME/$HOME}"
    # or
    expanded_str2=$(echo "$str" | sed "s!\$HOME!$HOME!")
    # or
    expanded_str2=$(echo "$str" | perl -plE 's/\$(\w+)/$ENV{$1}/g')
    # or ... other ways...
    

    Using

    echo "$expanded_str2"
    

    prints

    /Users/jm/tmp/somefile