2

I have two plist files given by two customers and each times I have to update it manually.

First one I can extract the string I need.

defaults read /Applications/TestAPP/info.plist TestValue
TESTAPP-TESTAPP-TESTAPP

Second one I need to append the previous result at the end of an array inside the second file.

defaults read /Applications/SecondTestAPP/info.plist TestValue2 
  <key>TEST</key>
    <array>
        <string>FIRSTONE</string>
        <string>SECONDONE</string>
        <string>THIRDONE</string>
    </array>
</dict> 

And I need to add TESTAPP-TESTAPP-TESTAPP after <string>THIRDONE</string>
Any ideas ?
I already tried: defaults write /Applications/SecondTestAPP/info.plist '<dict><key>TestValue</key><array><string>TESTAPP-TESTAPP-TESTAPP</string></array></dict>'
But it's not working.

Thomas Ayoub
  • 29,063
  • 15
  • 95
  • 142
VivienG
  • 2,143
  • 3
  • 24
  • 43

2 Answers2

7

Use plutil

Let's start with a plist:

> defaults write org.my.test '{aDict = {anArray = ();};}'

Use plist -p to print the plist to stdout.

plutil -p ~/Library/Preferences/org.my.test.plist
{
  "aDict" => {
    "anArray" => [
    ]
  }
}

Use plist -insert to add something to the array

> plutil -insert aDict.anArray.0 -string a ~/Library/Preferences/org.my.test.plist
> plutil -p ~/Library/Preferences/org.my.test.plist
{
  "aDict" => {
    "anArray" => [
      0 => "a"
    ]
  }
}

Your life will be better if you can insert the new item at the head of the list with index 0.

> plutil -insert aDict.anArray.0 -string before_a ~/Library/Preferences/org.my.test.plist
> plutil -p ~/Library/Preferences/org.my.test.plist
{
  "aDict" => {
    "anArray" => [
      0 => "before_a"
      1 => "a"
    ]
  }
}

But if you must put it at the end, then you need to figure out the length of the array. We will do this by first getting the array by itself.

> plutil -extract aDict.anArray json -o - ~/Library/Preferences/org.my.test.plist
["before_a","a"]

To get the number of elements, you can count the number of ',' and then add 1 - but this will have errors if the strings have commas in them.

> echo "$(plutil -extract aDict.anArray json -o - ~/Library/Preferences/org.my.test.plist | grep -F -o ',' | wc -l) + 1" | bc
2

Or you can install jq, a command line tool for reading and manipulating json.

> brew install jq
> plutil -extract aDict.anArray json -o - ~/Library/Preferences/org.my.test.plist | jq '. | length'
2

Then you can use that value to append your value to the end of the array.

> plutil -insert aDict.anArray.$(plutil -extract aDict.anArray json -o - ~/Library/Preferences/org.my.test.plist | jq '. | length') -string b ~/Library/Preferences/org.my.test.plist
> plutil -p ~/Library/Preferences/org.my.test.plist
{
  "aDict" => {
    "anArray" => [
      0 => "before_a"
      1 => "a"
      2 => "b"
    ]
  }
}

You'll also want to use plutil to get the value from the other plist

> plutil -extract KEYPATH json -o - OTHER_PLIST
YOUR_VALUE
> plutil -insert aDict.anArray.$(plutil -extract aDict.anArray json -o - ~/Library/Preferences/org.my.test.plist | jq '. | length') -string $(plutil -extract KEYPATH json -o - OTHER_PLIST) ~/Library/Preferences/org.my.test.plist
> plutil -p ~/Library/Preferences/org.my.test.plist
{
  "aDict" => {
    "anArray" => [
      0 => "before_a"
      1 => "a"
      2 => "b"
      3 => "YOUR_VALUE"
    ]
  }
}

It's a bit long, but a one-liner nonetheless.

Liyan Chang
  • 7,721
  • 3
  • 39
  • 59
  • 1
    Nice examples, but you missed that keypaths are supporting `count`. So you could count the number of array elements with something like `plutil -extract aDict.anArray.count xml1 -o - ~/Library/Preferences/org.my.test.plist|sed -n '/integer/s/[^0-9]//gp'` without relying on `jq` being installed. – David Ongaro Jan 09 '19 at 07:41
0

Ok, just tested this on 10.14 (beta) and 10.13.6 and it works for a simple plist:

General format is:

defaults write YOUR_PATH_TO_PLIST/PLIST.INFO ARRAY_KEY_NAME -array-add VALUE_TO_ADD

Or in this particular case:

defaults write /Applications/SecondTestAPP/info.plist TEST -array-add TESTAPP-TESTAPP-TESTAPP

For a more complex plist (e.g. something with lots of sub-dicts, etc), plutil is advised or using the built-in plist editing functions in python.