J'écris un script pour remplacer une URL de base dans un vidage de base de données par une autre URL de base (pour transférer le contenu de la base de données de Wordpress vers un autre hôte). Le remplacement de l'URL est la partie la plus facile (actuellement avec sed).

Cependant, il y a un problème avec les valeurs de la table d'options de Wordpress, qui stocke les chaînes au format PHP sérialisé, produisant quelque chose comme ...;s:6:\"abcdef\";s:3:\"zzz\";... (chaîne de type variable, longueur 6 et 3, valeur "abcdef" et "zzz") . Ainsi, chaque fois que la longueur de l'ancienne et de la nouvelle URL de base diffère, cette valeur d'option ne sera pas chargée, car la longueur de chaîne donnée ne correspond plus à la longueur de la chaîne réelle.

C'est donc la partie où awk entre en jeu: j'essaie de faire correspondre chaque chaîne du format s:number:\"baseurl/some_path\" et de remplacer le nombre par la longueur réelle de la chaîne baseurl/some_path, pour mettre à jour les valeurs de longueur de chaîne.

La commande awk que j'ai reçue jusqu'à présent est:

awk '{print gensub(/s:([0-9]+):\\"([^\\"]*)\\"/, sprintf("s:%d:\\\\\"%s\\\\\"", length("\\2"), "\\2"), "g") }' db_content_file

Mais cela génère des longueurs de chaîne de 2, quelle que soit la chaîne réelle, donc je suppose que \2 est littéralement passé à la fonction length, sans le remplacer par la chaîne stockée dans \2. Est-il en quelque sorte possible d'imposer un tel remplacement? Ou devrais-je utiliser un autre outil?

3
patpir 30 déc. 2015 à 22:35

3 réponses

Meilleure réponse

Malheureusement, des points-virgules peuvent apparaître dans des URL valides, donc l'utilisation de split () ne fonctionnera pas.

Il semble donc que vous deviez soit utiliser PHP pour désérialiser et re-sérialiser, soit analyser la chaîne sérialisée. Selon votre description, les éléments suivants devraient faire l'affaire:

awk '
  # Recompute the string lengths in a serialization in which strings
  # are represented by segments such as: s:6:\"abcdef\";
  # WARNING: the array a is global
  function repopulate(s, a1,n) { 
    # match(string, regexp [, array])
    # a[1] is set to the substring matching the first parenthesized subexpresssion, etc
    n = match(s, /s:[0-9]+:\\"([^\\"]*)\\";(.*)/, a);
    if (n<=0) {return s;}
    a1=a[1]; 
    return substr(s,1,n-1) "s:" length(a1) ":\\\"" a1 "\\\";" repopulate(a[2])
  }

  { print repopulate($0) }'
2
peak 31 déc. 2015 à 03:31

Si vous avez gawk, vous pouvez utiliser match

Par exemple

$ awk 'BEGIN{ match("s:22:\"baseurl/somepath\"", \
                    /s:([0-9]+):\"(.+)\"/,a);    \
              print length(a[2])}'


16

Je suppose que vous pouvez le prendre d'ici ...

0
karakfa 30 déc. 2015 à 22:55

Ce serait beaucoup plus facile si vous pouviez effectuer chaque remplacement de / vers en une seule étape, comme ceci:

awk -v from="http://one.com" -v to="http://two.two.org" '
  { from = "s:([0-9]+):\"" from "\";";
    to   = "s:" length(to) ":\"" to "\";";
    gsub(from, to);
    print; }'

Cela présente également l'avantage de ne pas nécessiter de awk spécial, tout en conservant l'avantage de ne pas exiger que les spécifications de longueur initiales soient correctes.

0
peak 30 déc. 2015 à 23:14