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