web-dev-qa-db-fra.com

Comment remplacer un champ particulier dans un fichier en fonction du contenu d'un autre champ?

J'ai un fichier au format suivant:

A 485C72F95C72E15C EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

Je veux fournir la lettre dans la première colonne en utilisant la valeur de la variable 'lettre' et remplacer la valeur dans la deuxième colonne par une valeur que je fournis dans la variable 'id'. La troisième colonne peut différer ou ne pas correspondre dans tous les cas. Les première et deuxième colonnes ne contiendront jamais d'espaces ni de caractères spéciaux.

J'ai essayé d'utiliser sed, mais mon sed-fu n'est pas puissant. Je suis venu avec ceci:

letter=A
id=MYNEWIDSTRING
sed "/$letter /s/[^ ]*/$id/2"

La sortie est:

A MYNEWIDSTRING EXTERNAL
B MYNEWIDSTRING SYSTEM
C EC2A63F12A63B76C EXTERNAL

L'identifiant est remplacé sur deux lignes, je suppose que cela est dû à la correspondance de 'A' à la fin de la chaîne d'identifiant d'origine.

Je sais utiliser sed -i pour éditer le fichier in-situ, mais je ne le fais pas encore, car ma commande est encore un peu louche.

Où est-ce que je me suis trompé ou devrais-je utiliser une méthode différente?

4
Arronical

Ancrez-le (^ est le début de la ligne) de sorte que le A ne corresponde que s'il s'agit du premier caractère:

$ letter=A; id=MYNEWIDSTRING; sed "/^$letter /s/[^ ]*/$id/2" file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

soit dit en passant, si vous voulez passer des variables à sed mais que vous avez besoin de guillemets serrés, souvenez-vous que vous pouvez activer et désactiver les guillemets tout en ajoutant des guillemets doubles pour les variables - moche mais probablement meilleure pratique en général:

sed '/^'"$letter"' /s/[^ ]*/'"$id"'/2'
5
Zanna

Chaque fois que vous avez affaire à des données structurées, j'atteins plutôt awk ou Perl plutôt que sed.

Par exemple

awk -v letter="A" -v id="MYNEWIDSTRING" '$1 == letter {$2=id}1' file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

ou

Perl -alne '
  BEGIN{$letter = shift; $id = shift;} 
  print join " ", $F[0], $F[0] eq $letter ? $id : $F[1], @F[2..$#F]
' 'A' 'MYNEWIDSTRING' file

Les versions les plus récentes de GNU awk ont ​​un indicateur -i (--in-place); dans d'autres, vous devrez utiliser un fichier temporaire explicite; Perl devrait avoir un -i dans tous les cas.

5
steeldriver