0 votos

Recoge los marcadores de Safari 'programáticamente' usando PlistBuddy

Tarea prevista y limitaciones sobre el interruptor -c de PlistBuddy

PlistBuddy imprimirá múltiples entradas de un archivo plist dado a la vez (en este ejemplo Bookmarks.plist). En realidad, el modificador -c sólo admite un comando por invocación. No admite múltiples comandos de una sola vez (es decir, invocando a PlistBuddy con un solo -c que contiene varios comandos separados por coma o punto y coma como en el inventó ejemplo más abajo):

# 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

De hecho, cada comando (es decir Print , Set , Add , Delete etc.) tiene que ser invocado con su -c switch:

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

Un ejemplo real para Bookmarks.plist tiene este aspecto:

/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

Obtener numerosas entradas del archivo plist de esta manera requeriría invocar docenas o incluso cientos de -c statements . ¡Tedioso!

Solución aspirada: hacerlo programáticamente usando printf, expansión de llaves y xargs

Mi planteamiento es conseguirlo de forma programada combinando printf , ampliación de la abrazadera {1..n} (rangos) y xargs .

La siguiente línea debería hacer toda la magia. echo es decir, invocar un funcionamiento en seco se utiliza para comprobar primero la sintaxis adecuada:

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

Perfecto, el resultado es el esperado:

/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

Examinemos los detalles para una mejor comprensión

printf necesita -- como primera opción para manejar el guión inicial de -c correctamente.
La gama entre llaves {1..50} se interpolará a 1, 2, 3, […], 50

El printf declaración...

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

...nos dará el siguiente resultado (interpolado):

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

Una mirada más cercana a la xargs parte:

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

Invocando xargs sin argumentos toma una lista de STDIN (un argumento por línea) y lo pasa (en grupos) a otro comando. El objetivo principal es que todos los valores sean adjunto (puede pensarse como añadir una cola) al final de comando .

Según este hilo :

-I cambia la forma en que se construyen las nuevas líneas de comando. En lugar de añadir todos los argumentos posibles a la vez, xargs tomará un nombre a la vez de su entrada, buscará el token dado ( {} aquí) y sustituirlo por el nombre.

El -0 en su ejemplo instruye a xargs a dividir su entrada en bytes nulos en lugar de espacios en blanco o nuevas líneas.

Esto es exactamente lo que se necesita; un tipo de inserción entre PlistBuddy y File y un manejo adecuado de los espacios en blanco:

PlistBuddy {INSERTED COMMANDS} File

COMANDOS INSERTADOS es el lugar donde todos los -c interruptores debe ser "insertado" por xargs .

El problema:

La invocación de este comando sin el echo arroja el siguiente error:

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:

Pero invocar el resultado con copiar y pegar o pasarlo a un archivo y ejecutarlo como 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

... da una lista de marcadores sin problemas:

https://apple.stackexchange.com
https://www.stackoverflow.com
https://www.google.com
https://www.youtube.com

Una solución aún mejor es canalizar todo el resultado a un shell:

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

Sí, es una solución inteligente, pero sigue siendo una solución.

Pregunta

¿Qué falta o cómo debe ser el comando para que se ejecute correctamente dentro del shell (sin la solución de copiar y pegar o la redirección a un segundo shell mediante una tubería)?

0voto

thewhodidthis Puntos 1

Puede que esté malinterpretando la pregunta, pero si tu objetivo es sacar algunos datos de plist(5), ¿has considerado seguir el camino de xpath(1)? Por ejemplo, lo siguiente trataría de convertir primero una copia de Bookmarks.plist en XML y luego atravesar ese árbol buscando URLs en una hipotética carpeta de bookmarks "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

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X