1 votes

Supprimer plusieurs lignes dans un fichier csv

Je travaille sur cette mission pour supprimer les lignes d'un fichier CSV avec différents clients. J'ai trouvé comment supprimer un client spécifique en utilisant ce code :

delete() {
  awk -F "\"*;\"*" '$1 != '$@' {print $ALL}' input.csv > output.csv
}

delete $@

Cependant, je dois maintenant supprimer plusieurs clients en même temps. Je peux identifier un client par son numéro de client qui est stocké dans la première colonne du fichier csv. Je suis censé créer un tableau pour les différents numéros de clients et créer une boucle while pour parcourir le tableau, mais je n'y arrive pas.

2voto

steeldriver Points 118154

Je ne sais pas pourquoi vous enveloppez cela dans une fonction Shell - je suppose que c'est une exigence de votre mission.

Tout d'abord, notez que l'utilisation de "*;"* en tant que séparateur de champ dans Awk n'est pas un moyen robuste de gérer les champs CSV entre guillemets - il échouera par exemple si le premier champ ou le dernier champ d'une ligne est entre guillemets, et il ne préservera pas les délimiteurs entre guillemets (c'est-à-dire les champs entre guillemets qui contiennent réellement un caractère ; ), ce qui va à l'encontre de l'intérêt de citer les champs CSV.

Deuxièmement, vous ne devriez pas essayer de passer des variables Shell (ou des paramètres positionnels) dans une expression Awk de cette manière - la manière correcte est soit de les exporter et ensuite d'y accéder via la fonction ENVIRON ou utilisez l'option de ligne de commande -v . Ainsi, votre implémentation "client unique" serait mieux écrite.

delcust() {
  awk -F '"*;"*' -v cust="$1" '$1 != cust' input.csv > output.csv
}
delcust "$1"

Pendant que vous pourrait modifier ceci pour passer plusieurs paramètres positionnels, je suggérerais de passer la liste des clients via l'entrée standard et de l'analyser comme un fichier de valeurs ; de cette façon, vous pouvez faire une recherche Awk canonique basée sur un tableau associatif (ou un hachage) :

delcusts() {
  printf '%s\n' "$@" | awk -F'"*;"*' 'NR==FNR {custs[$0]=1; next} !($1 in custs)' - input.csv > output.csv
}
delcusts "$@"

Notez que vous n'avez pas besoin d'un print en Awk depuis print est l'action par défaut si une règle est évaluée non nulle.

0voto

Sebastian Stark Points 5932

Il n'y a pas vraiment besoin d'un tableau. Vous pourriez définir votre fonction comme ceci :

delete() {
  awk -v customer="^($1)\$" -F ";" '$1 !~ customer {print $ALL}' input.csv >output.csv 
}

Je n'ai pas compris comment vous avez défini le séparateur de champs, alors je l'ai modifié pour pouvoir le tester. La partie pertinente consiste à utiliser une expression régulière négativée !~ . J'ai également utilisé le -v pour awk qui peut vous épargner bien des maux de tête liés aux citations Shell.

Avec cela, vous pouvez utiliser un paramètre comme celui-ci pour supprimer plusieurs clients :

delete 'bla|foo'

Pour dans input.csv comme ceci :

bla;blu;bli
foo;faa;fii
blafoo;blufaa;blifii

cela donnerait

blafoo;blufaa;blifii

dans le fichier output.csv.

Si vous voulez vraiment utiliser un tableau, vous pouvez en outre définir une petite fonction d'aide qui prépare le tableau à être utilisé avec la fonction delete() fonction ci-dessus :

join() { local IFS=\|; echo "$*"; }

Avec cela, vous êtes en mesure de définir un tableau bash et de le convertir en syntaxe alternative regex :

$ a=(bla blu)
$ join ${a[@]}
bla|blu

Vous pourriez alors appeler delete() comme ça :

$ a=(customer1 customer2)
$ delete "$(join ${a[@]})"

(Petit aparté pour les utilisateurs de zsh : la fonction join() n'est pas nécessaire pour zsh, vous pouvez simplement utiliser l'expansion de paramètres suivante : ${(j:|:)a} pour joindre tous les éléments du tableau avec le | caractère)

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