Est-il possible de remplacer la valeur d'une cellule dans un fichier csv à l'aide de grep,sed, ou les deux

0

La question

J'ai écrit la commande suivante

#!/bin/bash
awk -v value=$newvalue -v row=$rownum -v col=1 'BEGIN{FS=OFS=","} NR==row {$col=value}1' "${file}".csv >> temp.csv && mv temp.csv "${file}".csv

D'Entrée d'échantillon de fichier.csv

Header,1
Field1,Field2,Field3
1,ABC,4567
2,XYZ,7890

Assuiming $newvalue=3 ,$rownum=4 et col=1, alors le code ci-dessus va remplacer:

De Sortie Requis

Header,1
Field1,Field2,Field3
1,ABC,4567
3,XYZ,7890

Donc, si je sais que la ligne et la colonne, est-il possible de remplacer le dit de la valeur à l'aide de grep, sed?

Edit1: Field3 aura toujours une valeur unique pour leurs lignes respectives. ( dans le cas ou l'info aide de toute façon)

bash csv git-bash linux
2021-11-24 06:52:47
3

La meilleure réponse

1

En supposant que votre fichier CSV est aussi simple que ce que vous montrez (pas de virgule dans la cité des champs), et votre newvalue ne pas contenir de caractères sed pour les interpréter d'une manière spéciale (par exemple, les esperluettes, barres ou barres obliques inverses), les éléments suivants doivent travailler avec sed (testé avec GNU sed):

sed -Ei "$rownum s/[^,]*/$newvalue/$col" file.csv

Démo:

$ cat file.csv
Header,1
Field1,Field2,Field3
1,ABC,4567
3,XYZ,7890
$ rownum=3
$ col=2
$ newvalue="NEW"
$ sed -Ei "$rownum s/[^,]*/$newvalue/$col" file.csv
$ cat file.csv
Header,1
Field1,Field2,Field3
1,NEW,4567
3,XYZ,7890

Explications: $rownum est utilisé comme adresse (ici le numéro de la ligne) où appliquer la commande suivante. s est le sed commande de substitution. [^,]* est l'expression régulière pour rechercher et remplacer: la plus longue chaîne de caractères ne contenant pas d'une virgule. $newvalue est la chaîne de remplacement. $col est l'événement à remplacer.

Si newvalue peut contenir des arobases, barres ou barres obliques inverses, nous devons assainir d'abord:

sanitizednewvalue=$(sed -E 's/([/\&])/\\\1/g' <<< "$newvalue")
sed -Ei "$rownum s/[^,]*/$sanitizednewvalue/$col" file.csv

Démo:

$ newvalue='NEW&\/&NEW'
$ sanitizednewvalue=$(sed -E 's/([/\&])/\\\1/g' <<< "$newvalue")
$ echo "$sanitizednewvalue"
NEW\&\\\/\&NEW
$ sed -Ei "$rownum s/[^,]*/$sanitizednewvalue/$col" file.csv
$ cat file.csv
Header,1
Field1,Field2,Field3
1,NEW&\/&NEW,4567
3,XYZ,7890
2021-11-24 11:13:43

Ce n'travail. Juste quelques conseils cependant: je n'était pas au courant avant que cette réponse de "[ ^ ,] * " mais si sed est capable de le remplacer pour une cellule spécifique, alors pourquoi sommes-nous y compris [^,]* . Je l'ai fait essayer sed -Ei "$rownum s/$newvalue/$col" file.csv et il a jeté une erreur, mais aimeriez en savoir plus à ce sujet. Toute ressource à lire, à être utile.
Helium

Nous avons besoin de "[ ^ ,] * " parce que c'est ce qui définit ce qu'est une cellule de est. sed n'est pas un CSV processeur, c'est un tout-traitement de texte. Donc, il n'a pas connaissance de ce que vous appelez une cellule de est. Nous devons le dire. Le sed commande de substitution (s) est expliqué en profondeur les détails dans le sed manuel que vous trouverez facilement (si vous êtes sous GNU/Linux ou macOS essayer man sed ou, encore mieux, info sed). La commande de substitution-vous essayé est syntaxiquement incorrect, donc l'erreur.
Renaud Pacalet

Yup, qui fait plus de sens maintenant, lorsqu'on le met comme ça.
Helium
1

Avec sedcomment sur:

#!/bin/bash

newvalue=3
rownum=4
col=1

sed -i -E "${rownum} s/(([^,]+,){$((col-1))})[^,]+/\\1${newvalue}/" file.csv

Résultat de file.csv

Header,1
Field1,Field2,Field3
1,ABC,4567
3,XYZ,7890
  • ${rownum} correspond au numéro de ligne.
  • (([^,]+,){n}) correspond à la n de temps de répétition du groupe de non-virgule caractères suivis d'une virgule. Ensuite, il convient de la sous-chaîne avant de la cible (à remplacer) de la colonne par l'affectation de npour col - 1.
2021-11-24 07:21:19

même si cela fonctionne, n'est-ce pas un peu plus compliqué de faire les choses par rapport à la façon dont Renauld de réponse. Comme, pourquoi avons-nous besoin pour correspondre à la n de temps de répétition si l'on peut, au lieu de directement de le remplacer? Néanmoins utile
Helium
0

Nous allons Essayer de mettre en Œuvre sed commande

Considérons un exemple de fichier CSV avec le contenu suivant:

$ cat file

Solaris,25,11
Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,12,5
  1. Pour supprimer la 1re ou de la colonne :
$ sed 's/[^,]*,//' file

25,11
31,2
21,3
45,4
12,5

Cette expression régulière recherches pour une séquence de non-virgule([^,]*) les personnages et les supprime ce qui entraîne dans le 1er champ d'obtenir supprimé.

  1. Pour imprimer uniquement le dernier champ, OU supprimer tous les champs sauf le dernier champ:
$ sed 's/.*,//' file

11
2
3
4
5

Cette regex supprime tout jusqu'à la dernière virgule(.*,) qui entraîne la suppression de tous les champs sauf le dernier champ.

  1. Pour imprimer uniquement le 1er champ:
$ sed 's/,.*//' file

Solaris
Ubuntu
Fedora
LinuxMint
RedHat

Cette regex(,.*) supprime les caractères à partir du 1er virgule jusqu'à la fin entraînant la suppression de tous les champs sauf le dernier champ.

  1. Pour supprimer le 2ème champ:
$ sed 's/,[^,]*,/,/' file

Solaris,11
Ubuntu,2
Fedora,3
LinuxMint,4
RedHat,5

La regex (,[^,]*,) recherche d'une virgule et de la séquence de caractères suivie d'une virgule qui résultats dans la correspondance de la 2ème colonne, et qui remplace ce modèle associé à une virgule, terminant finalement à la suppression de la 2ème colonne.

Remarque: Pour supprimer les champs dans le milieu devient de plus en plus tendue dans sed, car chaque champ doit correspondre à la lettre.

  1. Pour imprimer uniquement le 2e champ:
$ sed 's/[^,]*,\([^,]*\).*/\1/' file

25
31
21
45
12

L'expression régulière correspond à la première zone, le deuxième champ et le reste, cependant, des groupes de la 2ème seul domaine. L'ensemble de la ligne est maintenant remplacé par le 2e champ(\1), donc seul le 2ème champ est affiché.

  1. Imprimer uniquement les lignes dont la dernière colonne est un seul chiffre:
$ sed -n '/.*,[0-9]$/p' file

Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,12,5

La regex (,[0-9]$) vérifie la présence d'un seul chiffre dans le dernier champ et de la commande p imprime la ligne qui correspond à cette condition.

  1. Au nombre de toutes les lignes dans le fichier:
$ sed = file | sed 'N;s/\n/ /'

1 Solaris,25,11
2 Ubuntu,31,2
3 Fedora,21,3
4 LinuxMint,45,4
5 RedHat,12,5

C'est la simulation de la cat-n de commande. awk est-il facilement à l'aide de la variable NR. Le '=' commande des sed donne le numéro de ligne de chaque ligne suivie par la ligne elle-même. Le sed de sortie est redirigée vers une autre commande sed pour rejoindre toutes les 2 lignes.

  1. Remplacer le dernier champ de 99 si le 1er champ est 'Ubuntu':
$ sed 's/\(Ubuntu\)\(,.*,\).*/\1\299/' file

Solaris,25,11
Ubuntu,31,99
Fedora,21,3
LinuxMint,45,4
RedHat,12,5

Cette expression correspond 'Ubuntu' et jusqu'à la fin, sauf la dernière colonne et groupes, chacun d'eux ainsi. Dans la pièce de remplacement, le 1er et le 2ème groupe avec le nouveau numéro 99 est remplacé.

  1. Supprimer la 2ème champ si le 1er champ est "RedHat':
$ sed 's/\(RedHat,\)[^,]*\(.*\)/\1\2/' file

Solaris,25,11
Ubuntu,31,2
Fedora,21,3
LinuxMint,45,4
RedHat,,5

Le 1er champ "RedHat", le 2ème champ et les champs restants sont regroupés, et le remplacement est effectué avec uniquement le 1er et le dernier groupe , resuting dans l'obtention de la 2ème champ supprimé.

  1. Pour insérer une nouvelle colonne à la fin(dernière colonne) :
$ sed 's/.*/&,A/' file

Solaris,25,11,A
Ubuntu,31,2,A
Fedora,21,3,A
LinuxMint,45,4,A
RedHat,12,5,A

La regex (.*) correspond à l'ensemble de la ligne et de la remplacer par la ligne elle-même (&) et le nouveau champ.

  1. Pour insérer une nouvelle colonne dans le début(1ère colonne):
$ sed 's/.*/A,&/' file

A,Solaris,25,11
A,Ubuntu,31,2
A,Fedora,21,3
A,LinuxMint,45,4
A,RedHat,12,5

Dernier exemple, la ligne appariés est suivie par la nouvelle colonne

J'espère que cela aidera. Laissez-moi savoir si vous avez besoin d'utiliser Awk ou toute autre commande. Merci

2021-11-24 07:36:29

merci pour l'explication détaillée, mais malheureusement, ça ne résout pas le problème à la main.
Helium

Dans d'autres langues

Cette page est dans d'autres langues

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................