11.5 C
Tuesday, February 20, 2024

Acquire Safari Bookmarks ‘programmatically’ utilizing PlistBuddy

Supposed process and limitations about PlistBuddy’s -c change

PlistBuddy shall print a number of entries of a given plist file directly (on this instance Bookmarks.plist). Really, the -c change helps solely one command per invocation. It doesn’t help a number of instructions in a single shot (i. e. invoking PlistBuddy with a single -c containing a number of instructions separated by coma or semicolon like within the invented instance beneath):

# Invented command, do not strive it, it would not work!

/usr/libexec/PlistBuddy -c 'Print :Entry1, Print :Entry2, Print :…'      # A number of instructions separated by comma would not work
/usr/libexec/PlistBuddy -c 'Print :Entry1; Print :Entry2; Print :…'      # A number of instructions separated by semikolon would not work both

In actual fact, each command (i. e. Print, Set, Add, Delete and so forth) needs to be invoked with its devoted -c change:

/usr/libexec/PlistBuddy -c 'Print :Entry1' -c 'Print :Entry2' -c 'Print :…'      # Propper invocation to get the values for Entry{1,2,…}

An actual instance for Bookmarks.plist appears like this:

/usr/libexec/PlistBuddy -c 'Print :Kids:1:Kids:1:URLString' -c 'Print :Kids:1:Kids:2:URLString' -c 'Print :Kids:1:Kids:3:URLString' Bookmarks.plist

Getting quite a few entries from plist file this fashion would require invoking dozens and even tons of of -c statements. Tedious!

Aspired resolution: doing it programmatically utilizing printf, brace growth and xargs

My method is to attain this programmatically by combining printf, brace growth {1..n} (ranges) and xargs.

The next line ought to do the entire magic. echo, i. e. invoke a dry-run, is used to examine the correct syntax first:

printf -- "-c 'Print :Kids:1:Kids:%d:URLString' " {1..50} | xargs -0I{} echo /usr/libexec/PlistBuddy {} Bookmarks.plist

Good, the result’s as anticipated:

/usr/libexec/PlistBuddy -c 'Print :Kids:1:Kids:1:URLString' -c 'Print :Kids:1:Kids:2:URLString' -c 'Print :Kids:1:Kids:3:URLString' -c 'Print :Kids:1:Kids:4:URLString' Bookmarks.plist

Allow us to look at the main points for a greater understanding

printf wants -- as first possibility with the intention to deal with the main hyphen from -c correctly.
The vary in braces {1..50} will probably be interpolated to 1, 2, 3, […], 50

The printf assertion…

printf -- "-c 'Print :Kids:1:Kids:%d:URLString' " {1..50}

…will give us the next (interpolated) end result:

-c 'Print :Kids:1:Kids:1:URLString' -c 'Print :Kids:1:Kids:2:URLString' […] -c 'Print :Kids:1:Kids:50:URLString' 

A more in-depth have a look at the xargs half:

xargs -0I{} echo /usr/libexec/PlistBuddy {} Bookmarks.plist

Invoking xargs with none arguments takes a listing from STDIN (one argument per line) and passes it (in teams) to a different command. The primary focus is that each one values are appended (will be thought as appending a tail) on the finish of command.

In accordance with this thread:

-I possibility adjustments the best way the brand new command strains are constructed.
As an alternative of including as many arguments as attainable at a time, xargs
will take one identify at a time from its enter, search for the given token
({} right here) and change that with the identify.

The -0 possibility in your instance instructs xargs to separate its enter on null bytes as an alternative of blanks or newlines.

That is precisely what is required; a type of insertion between PlistBuddy and File and a correct dealing with of white areas:


INSERTED COMMANDS is the place the place all -c switches ought to be “inserted” by xargs.


Invoking this command with out the echo throws the next error:

File Does not Exist, Will Create:  
-c 'Print :Kids:1:Kids:1:URLString' -c 'Print Kids:1:Kids:2:URLString' -c 'Print :Kids:1:Kids:3:URLString' -c 'Print :Kids:1:Kids:4:URLString'<br />

However invoking the end result with copy and paste or piping it to a file and executing it as shell script…

printf -- "-c 'Print :Kids:1:Kids:%d:URLString' " {1..4} | xargs -0I{} echo /usr/libexec/PlistBuddy {}Bookmarks.plist > testing.sh && supply ./testing.sh

… offers a listing of bookmarks with none points:


An excellent higher workaround is to pipe the entire end result to a shell:

printf -- "-c 'Print :Kids:1:Kids:%d:URLString' " {1..4} | xargs -0I{} echo /usr/libexec/PlistBuddy {}Bookmarks.plist | sh -

Sure, its a wise workaround, nevertheless it’s nonetheless a workaround.


What’s lacking or how should the command appear like to be correctly executed inside the shell (with out the workaround of copy and paste or redirection right into a second shell through pipe)?

Latest news
Related news


Please enter your comment!
Please enter your name here