0 votes

Recueillir les signets de Safari de manière "programmatique" avec PlistBuddy

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) ?

0voto

GregInWI2 Points 484

J'ai peut-être mal interprété la question, mais si votre objectif est d'extraire des données plist(5), avez-vous envisagé d'utiliser la méthode xpath(1) ? Par exemple, ce qui suit essaierait d'abord de convertir une copie de Bookmarks.plist en XML, puis de parcourir cet arbre à la recherche d'URL dans un hypothétique dossier de signets "Public" :

#!/bin/sh

# Copy the plist somewhere temporary.
cp ~/Library/Safari/Bookmarks.plist /tmp/Bookmarks.plist

# Use the property list utility to convert the copy to XML.
plutil -convert xml1 /tmp/Bookmarks.plist

# Filter for URLs saved in "Public".
xpath -q -e '/plist/dict/array/dict/key[.="WebBookmarkType"]/following-sibling::string[.="WebBookmarkTypeList"]/preceding-sibling::key[.="Title"]/following-sibling::string[contains(text(),"Public")]/parent::node()/array/dict/key[.="URLString"]/following-sibling::string[1]/text()' /tmp/Bookmarks.plist

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X