Tâche prévue et limites de l'option -c de PlistBuddy
PlistBuddy imprimera plusieurs entrées d'un fichier plist donné en une seule fois (dans cet exemple Bookmarks.plist). En fait, le commutateur -c ne supporte que un commande par invocation. Il ne prend pas en charge les commandes en une seule fois (c'est-à-dire en invoquant PlistBuddy avec un simple -c
contenant plusieurs commandes séparées par une virgule ou un point-virgule comme dans l'exemple suivant a inventé exemple ci-dessous) :
# Invented command, don't try it, it doesn't work!
/usr/libexec/PlistBuddy -c 'Print :Entry1, Print :Entry2, Print :…' # Multiple commands separated by comma doesn't work
/usr/libexec/PlistBuddy -c 'Print :Entry1; Print :Entry2; Print :…' # Multiple commands separated by semikolon doesn't work either
En fait, chaque commande (i.e. Print
, Set
, Add
, Delete
et ainsi de suite) doit être invoquée avec sa propre fonction -c switch:
/usr/libexec/PlistBuddy -c 'Print :Entry1' -c 'Print :Entry2' -c 'Print :…' # Propper invocation to get the values for Entry{1,2,…}
Un exemple réel pour Bookmarks.plist ressemble à ceci :
/usr/libexec/PlistBuddy -c 'Print :Children:1:Children:1:URLString' -c 'Print :Children:1:Children:2:URLString' -c 'Print :Children:1:Children:3:URLString' Bookmarks.plist
Obtenir de nombreuses entrées du fichier plist de cette manière nécessiterait d'invoquer des dizaines, voire des centaines de -c statements
. Fastidieux !
Solution envisagée : le faire de manière programmatique en utilisant printf, l'expansion des accolades et xargs.
Mon approche consiste à réaliser cet objectif de manière programmatique en combinant les éléments suivants printf
, brace expansion {1..n}
(gammes) et xargs
.
La ligne suivante devrait faire toute la magie. echo
c'est-à-dire invoquer une essai à sec est utilisé pour vérifier d'abord la syntaxe correcte :
printf -- "-c 'Print :Children:1:Children:%d:URLString' " {1..50} | xargs -0I{} echo /usr/libexec/PlistBuddy {} Bookmarks.plist
Parfait, le résultat est conforme aux attentes :
/usr/libexec/PlistBuddy -c 'Print :Children:1:Children:1:URLString' -c 'Print :Children:1:Children:2:URLString' -c 'Print :Children:1:Children:3:URLString' -c 'Print :Children:1:Children:4:URLString' Bookmarks.plist
Examinons les détails pour mieux comprendre
printf
besoins --
en tant que première option afin de gérer le trait d'union de tête de l'option -c
correctement.
La gamme entre parenthèses {1..50}
sera interpolée en 1, 2, 3, […], 50
Le site printf
déclaration...
printf -- "-c 'Print :Children:1:Children:%d:URLString' " {1..50}
...nous donnera le résultat suivant (interpolé) :
-c 'Print :Children:1:Children:1:URLString' -c 'Print :Children:1:Children:2:URLString' […] -c 'Print :Children:1:Children:50:URLString'
Un regard plus attentif sur le xargs
partie :
xargs -0I{} echo /usr/libexec/PlistBuddy {} Bookmarks.plist
Invoquer xargs
sans aucun argument prend une liste de STDIN
(un argument par ligne) et le passe (en groupe) à une autre commande. L'objectif principal est que toutes les valeurs soient en annexe (peut être considéré comme l'ajout d'une queue) à la fin de commande .
Selon ce fil :
-I
L'option change la façon dont les nouvelles lignes de commande sont construites. Au lieu d'ajouter autant d'arguments que possible à la fois,xargs
prendra un nom à la fois dans son entrée, cherchera le jeton donné ({}
ici) et remplacez-la par le nom.Le site
-0
dans votre exemple indique à xargs de diviser son entrée sur les octets nuls au lieu des blancs ou des nouvelles lignes.
C'est exactement ce dont nous avons besoin ; une sorte d'insertion entre PlistBuddy et File et une gestion correcte des espaces blancs :
PlistBuddy {INSERTED COMMANDS} File
COMMANDES INSÉRÉES est l'endroit où tous les -c
interrupteurs devrait être "inséré" par xargs
.
Problème :
L'invocation de cette commande sans l'option echo
lance l'erreur suivante :
File Doesn't Exist, Will Create:
-c 'Print :Children:1:Children:1:URLString' -c 'Print Children:1:Children:2:URLString' -c 'Print :Children:1:Children:3:URLString' -c 'Print :Children:1:Children:4:URLString'<br />
Command:
Mais invoquer le résultat avec copier et coller ou en le pipant dans un fichier et en l'exécutant comme shell script...
printf -- "-c 'Print :Children:1:Children:%d:URLString' " {1..4} | xargs -0I{} echo /usr/libexec/PlistBuddy {}Bookmarks.plist > testing.sh && source ./testing.sh
... donne une liste de signets sans aucun problème :
https://apple.stackexchange.com
https://www.stackoverflow.com
https://www.google.com
https://www.youtube.com
Une solution encore plus efficace consiste à transmettre le résultat complet à un shell :
printf -- "-c 'Print :Children:1:Children:%d:URLString' " {1..4} | xargs -0I{} echo /usr/libexec/PlistBuddy {}Bookmarks.plist | sh -
Oui, c'est une solution de rechange intelligente, mais ça reste une solution de rechange.
Question
Que manque-t-il ou à quoi doit ressembler la commande pour être correctement exécutée dans le shell (sans la solution de contournement du copier-coller ou de la redirection vers un second shell via un pipe) ?