2 votes

Comment rechercher une chaîne de texte et l'insérer dans une variable en utilisant sed ?

Je dois mettre à jour des centaines de fichiers de configuration pour un programme en ajoutant de nouvelles lignes dans des fichiers texte. Je vais ajouter des propriétés supplémentaires, telles que la couleur de fond, à ces fichiers et je veux automatiser le processus avec bash. Toutes ces propriétés sont contenues dans des fichiers ".m". Il s'agit essentiellement de la mise à jour des propriétés des widgets sur les interfaces graphiques. Les propriétés de chaque objet dans une interface graphique sont étiquetées avec un type d'objet suivi d'un nom. Un exemple d'objet s'appelle un formulaire.

Le problème est que chaque nom qui suit l'objet est différent. Je dois donc ajouter la ligne en fonction du nom des autres propriétés dans chaque section du fichier .m. Par exemple, un fichier contient deux objets de formulaire. La section de l'un d'entre eux s'appelle "*FO_mm" tandis que la section du second objet s'appelle "*FO_test_area". Après le nom, il y a une extension pour la propriété spécifiée, comme "*FO_mm.class :". Bien que les propriétés de chaque objet tendent à varier, j'ai constaté que tous les objets partagent une propriété appelée ".parent", que j'utilise donc comme référence de recherche. Je veux utiliser la commande sed pour ajouter une ligne après la ligne .parent avec la nouvelle propriété, dans ce cas la couleur de fond. L'idée est donc de rechercher une chaîne qui commence par "*FO_" et se termine par ".parent", avec tout ce qui se trouve entre les deux étant quelque chose de différent pour chaque section. Je veux utiliser une boucle pour capturer la chaîne précédant ".parent" en tant que variable et l'attacher au début de la nouvelle ligne de propriété afin qu'elle corresponde à la section actuelle. Voici mon script actuel :

//The top level directory
script_dir="/project/guis/"
//The extension to look for
file_ext="*.m"
fileList=$(find $script_dir -type f -name "$file_ext")
declare -a file_list
readarray -t file_list < <(printf '%s\n' "$fileList")
cd $script_dir
//Loop through each m file
for m_file in ${file_list[@]}; do
        var1=($(grep '*FO_.*.parent:' $m_file))
        declare -a var_list
        readarray -t var_list < <(printf '%s\n' "$var1")
        for i in ${var_list[@]}; do
                echo $i
                sed -i "/^*FO_.*.parent:.*/a\$i.background: #2b3856 " $m_file
        done
done

Lorsque je l'exécute, le script ajoute la ligne "$i.background : #2b3856" sous la ligne .parent. Et la ligne "echo $i" renvoie "*FO_mm.parent : FO_mm". Il y a donc plusieurs problèmes.

  1. La valeur de la variable n'est pas substituée dans l'instruction sed.
  2. Comme l'indique l'écho, seule la première section "*FO_mm" est sauvegardée comme variable, ce qui signifie que la deuxième section "*FO_test_area" n'est pas mise en œuvre.
  3. Je veux seulement que le nom de l'objet soit stocké et placé dans la nouvelle ligne. Donc le résultat devrait me donner pour la première section "*FO_mm.background : #2b3856", tout ce qui est à partir de .background étant ajouté par la dernière partie de l'instruction sed. Comme je suis encore assez novice en matière de bash et surtout de sed, je n'ai aucune idée de la façon de réduire la variable au seul nom de l'objet.

Voici un exemple de ce à quoi ressemble une section d'objet unique avant l'exécution du script :

*FO_test_area.class: Form
*FO_test_area.static: true
*FO_test_area.parent: FO_mm
*FO_test_area.resizePolicy: "resize_none"

Et voici à quoi ressemble cette section après l'exécution du WIP script :

*FO_test_area.class: Form
*FO_test_area.static: true
*FO_test_area.parent: FO_mm
$i.background: #33b342
*FO_test_area.resizePolicy: "resize_none"

Il y a beaucoup à dire, mais je suis dans une impasse et j'apprécierais vraiment toute aide que vous pourriez m'apporter.

1voto

Jetchisel Points 3761

Si ed est disponible/acceptable.

Le script nommé script.ed (donnez-lui le nom que vous voulez).

g/^\*FO_.*\.parent:.*/t.\
s/^\(\*\).*parent: */\1/
s/$/.background: #33b342/
%p
Q

El g/^\*FO_.*\.parent:.*/ correspondra à toutes les lignes qui commencent par *FO_ et avec .parent: quelque part après. Il correspondra soit *FO_test_area.parent y *FO_mm.class.parent . Vous allez devoir être spécifique à propos de la regex pour correspondre à un spécifique *FO_.*\.parent: pour être capable de faire une recherche et remplacement/insertion


Voici un script spécifique pour la *FO_test_area.parent:

g/^\*FO_test_area\.parent:.*/t.\
s/^\(\*\).*parent: */\1/
s/$/.background: #33b342/
%p
Q

Modifier le script ci-dessus et ajouter un autre motif avant la ligne où %p se trouve, effectuez le reste de la substitution après cela.


Votre fichier/données d'exemple.

*FO_test_area.class: Form
*FO_test_area.static: true
*FO_test_area.parent: FO_mm
*FO_test_area.resizePolicy: "resize_none"

Exécution du script contre vos données/fichier. (fichier se terminant par un .m )

ed -s file.m < script.ed

Sortie

*FO_test_area.class: Form
*FO_test_area.static: true
*FO_test_area.parent: FO_mm
*FO_mm.background: #33b342
*FO_test_area.resizePolicy: "resize_none"

Si vous êtes satisfait du résultat, la prochaine étape est de faire la boucle.

Je fais quelques ajustements à votre script. Au lieu d'une imbrication for boucle, le script utilise une while + read boucle et Substitution de processus . Voir Comment lire un fichier (flux de données, variable) ligne par ligne (et/ou champ par champ) ?

#!/usr/bin/env bash

script_dir="/project/guis/"
file_ext="*.m"

while IFS= read -r m_file; do
  if grep -q '^\*FO_.*.parent:' "$m_file"; then
    ed -s "$m_file" < script.ed
  fi
done < <(find "$script_dir" -type f -name "$file_ext")

  • El script.ed est dans le répertoire courant où se trouve votre script. Il peut se trouver n'importe où, il suffit de lui donner le chemin absolu correct, par ex. /path/to/script.ed

  • Si en place Une modification est nécessaire pour changer le Q a w à l'intérieur de la ed script.

  • Supprimez la ligne où %p est à si la sortie n'est pas nécessaire pour stdout .


Voir :

Et aussi vos pages de manuel locales.

man 1p ed

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X