Hello
If PlistBuddy is not up to date to support recent preferences caching, here's a rubycocoa script using defaults(1) for reading plist and retrieve value at given key path. Key path is in the form as used in PlistBuddy except for using / instead of :.
E.g.,
./plist_read.rb '/Dictionary1/Dictionary2/Dictionary3-auto/Array1/0/String1' a.plist
# plist_read.rb
require 'osx/cocoa'
include OSX
def dict_get_value_at_path(dict, keypath)
v, p = dict, ''
keypath.split('/').select {|a| a.length > 0}.each do |k|
p << '/' + k
if v.className == 'NSCFDictionary' && v.key?(k)
v = v[k]
elsif v.className == 'NSCFArray' && k =~ /^\d+$/ && v[k.to_i]
v = v[k.to_i]
else
$stderr.puts '%s: No such key path.' % p
return nil
end
end
return v
end
raise ArgumentError, %Q[Usage: #{File.basename($0)} keypath plist] unless ARGV.length == 2
keypath, infile = ARGV
s = %x[defaults read "#{File.expand_path(infile).chomp('.plist')}"]
exit $? >> 8 if s == ''
plist = s.to_ns.propertyList
exit 1 unless plist
value = dict_get_value_at_path(plist, keypath)
exit 2 unless value
puts value
# test.sh (plist_read.rb is assumed to be saved in ~/desktop)
#!/bin/bash
cd ~/desktop
cat <<'EOF' > org.my.domain.plist
<?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>Dictionary1</key>
<dict>
<key>Dictionary2</key>
<dict>
<key>Dictionary3-auto</key>
<dict>
<key>Number1</key>
<integer>1</integer>
<key>Boolean1</key>
<true/>
<key>Array1</key>
<array>
<dict>
<key>String1</key>
<string>abc</string>
</dict>
<dict>
<key>String1</key>
<string>def</string>
</dict>
</array>
</dict>
</dict>
</dict>
</dict>
</plist>
EOF
./plist_read.rb '/Dictionary1/Dictionary2/Dictionary3-auto/Array1/0/String1' org.my.domain.plist
Just in case this might be of some use.
All the best,
H
PS. Here's another version of plist_read.rb using CFPreferencesAppSynchronize() which is not well-tested, for I'm using 10.6.8.
require 'osx/cocoa'
include OSX
def dict_get_value_at_path(dict, keypath)
v, p = dict, ''
keypath.split('/').select {|a| a.length > 0}.each do |k|
p << '/' + k
if v.className == 'NSCFDictionary' && v.key?(k)
v = v[k]
elsif v.className == 'NSCFArray' && k =~ /^\d+$/ && v[k.to_i]
v = v[k.to_i]
else
$stderr.puts '%s: No such key path.' % p
return nil
end
end
return v
end
raise ArgumentError, %Q[Usage: #{File.basename($0)} keypath plist] unless ARGV.length == 2
keypath, infile = ARGV
bundleid = File.basename(infile, '.plist')
b = CFPreferencesAppSynchronize(bundleid)
$stderr.puts 'CFPreferencesAppSynchronize() failed for %s' % bundleid unless b
plist = NSDictionary.dictionaryWithContentsOfFile(infile)
unless plist
$stderr.puts '%s: Failed to get dictionary.' % infile
exit 1
end
value = dict_get_value_at_path(plist, keypath)
exit 2 unless value
puts value