48 votes

sed : comment remplacer une ligne si elle est trouvée ou l'ajouter à la fin du fichier si elle n'est pas trouvée ?

Avec un seul fichier d'entrée qui ne contient que des commentaires (commençant par #) et des lignes VARIABLE=valeur, est-il possible de remplacer une valeur pour une seule variable si elle est trouvée et, dans le cas contraire, d'ajouter la paire à la fin du fichier si elle n'est pas trouvée ?

Ma méthode actuelle consiste à l'effacer dans un premier temps, puis à l'ajouter à la fin du fichier dans un second temps, mais cette méthode perturbe l'ordre des lignes (et il s'agit également de deux commandes différentes) :

sed -r "/^FOOBAR=.*$/d"      -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile

Existe-t-il un moyen de faire cela, c'est-à-dire de conserver l'ordre des lignes, en une seule ligne sed ? Si un autre utilitaire (awk, ...) fait cela, je le préférerais à sed.

0voto

Abbas Points 3737

C'est un peu plus facile en awk, bien que l'édition sur place ne soit pas automatique :

awk -v varname="FOOBAR" -v newval="newvalue" '
    BEGIN {FS = OFS = "="}
    $1 == varname {$2 = newval; found = 1}
    {print}
    END {if (! found) {print varname, newval}}
' file > tempfile &&
mv tempfile file

-1voto

Waqleh Points 109

Pour moi, j'ai essayé la plupart des solutions ci-dessus et elles n'ont pas fonctionné en utilisant sed (GNU sed) 4.4 ! J'ai donc essayé quelque chose de similaire à la solution de @snapshoe mais un peu différent :

envVar=FOOBAR
envVal=newvalue
file=samefile
grep -q "^${envVar}=" ${file} && sed -i -e "s/^${envVar}=.*/${envVar}=${envVal}/g" ${file} || echo "${envVar}=${envVal}" >> ${file}

Cela remplacera le FOOBAR s'il est trouvé ou l'ajoutera à la fin du fichier s'il n'est pas trouvé.

une ligne : envVar=FOOBAR && envVal=newvalue && file=samefile && grep -q "^${envVar}=" ${file} && sed -i -e "s/^${envVar}=.*/${envVar}=${envVal}/g" ${file} || echo "${envVar}=${envVal}" >> ${file}

-1voto

Happy Face Points 1

Sed hold ne peut gérer qu'une seule entrée. J'ai amélioré la réponse de glenn jackman pour gérer plusieurs entrées :

awk 'BEGIN {FS = OFS = "="}{idx=0;
  varname[++idx]="FOOBAR1";newval[idx]="val1";
  varname[++idx]="FOOBAR2";newval[idx]="val2";
  ...
}
{for (i in varname){if ($1 == varname[i]){sub($2".*",newval[i]);found[i]=1;}}print}
END {for (i in varname){if (!found[i]) print varname[i], newval[i]}
}' file > tempfile && cp tempfile file && rm tempfile

-2voto

antweiss Points 97

Pour faire cela avec perl et in-place, cela fonctionne très bien pour moi :

grep ^FOOBAR= my.file && perl -i -ple "s/^FOOBAR=.+/FOOBAR=newvalue/g" my.file || echo FOOBAR=newvalue >> my.file

-2voto

lee Points 353

Il fonctionne actuellement avec les éléments suivants : sed -i '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile Dans la réponse choisie, il manque -i.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X