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:
PlistBuddy {INSERTED COMMANDS} File
INSERTED COMMANDS is the place the place all -c
switches ought to be “inserted” by xargs
.
Drawback:
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 />
Command:
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:
https://apple.stackexchange.com
https://www.stackoverflow.com
https://www.google.com
https://www.youtube.com
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.
Query
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)?