J'ai besoin de supprimer 2 colonnes dans un fichier de valeurs séparées par des virgules. Considérez la ligne suivante dans le fichier csv:
"[email protected],www.example.com",field2,field3,field4
"[email protected]",field2,field3,field4
Maintenant, le résultat que je veux à la fin:
"[email protected],www.example.com",field4
"[email protected]",field4
J'ai utilisé la commande suivante:
awk 'BEGIN{FS=OFS=","}{print $1,$4}'
Mais la virgule intégrée qui se trouve entre guillemets crée un problème, voici le résultat que j'obtiens:
"[email protected],field3
"[email protected]",field4
Maintenant, ma question est de savoir comment faire pour que awk ignore les "," qui sont à l'intérieur des guillemets doubles?
Dans le manuel GNU awk ( http://www.gnu.org/software/gawk/manual/gawk.html#Splitting-By-Content ):
$ awk -vFPAT='([^,]*)|("[^"]+")' -vOFS=, '{print $1,$4}' file
"[email protected],www.example.com",field4
"[email protected]",field4
et voyez Quel est le moyen le plus robuste pour analyser efficacement CSV en utilisant awk? pour analyser plus généralement les CSV qui incluent des sauts de ligne, etc. dans les champs.
Ce n'est pas une solution bash/awk, mais je recommande CSVKit , qui peut être installé par pip install csvkit
. Il fournit une collection d'outils de ligne de commande pour travailler spécifiquement avec CSV, y compris csvcut
, qui fait exactement ce que vous demandez:
csvcut --columns=1,4 <<EOF
"[email protected],www.example.com",field2,field3,field4
"[email protected]",field2,field3,field4
EOF
Sortie:
"[email protected],www.example.com",field4
[email protected],field4
Il supprime les citations inutiles, ce qui, je suppose, ne devrait pas être un problème.
Lisez les documents de CSVKit ici sur RTD . ThoughtBot a un Joli petit billet de blog présentant cet outil, c'est là que j'ai découvert CSVKit.
Dans votre exemple de fichier d'entrée, c'est le premier champ et uniquement le premier champ, qui est cité. Si cela est vrai en général, considérez ce qui suit comme une méthode pour supprimer les deuxième et troisième colonnes:
$ awk -F, '{for (i=1;i<=NF;i++){printf "%s%s",(i>1)?",":"",$i; if ($i ~ /"$/)i=i+2};print""}' file
"[email protected],www.example.com",field4
"[email protected]",field4
Comme mentionné dans les commentaires, awk ne comprend pas nativement les séparateurs entre guillemets. Cette solution fonctionne autour de cela en recherchant le premier champ qui se termine par un devis. Il ignore ensuite les deux champs suivants.
for (i=1;i<=NF;i++)
Cela démarre un for
sur chaque champ i
.
printf "%s%s",(i>1)?",":"",$i
Ceci imprime le champ i
. S'il ne s'agit pas du premier champ, le champ est précédé d'une virgule.
if ($i ~ /"$/)i=i+2
Si le champ actuel se termine par un guillemet double, cela incrémente alors le compteur de champs de 2. C'est ainsi que nous sautons les champs 2 et 3.
print""
Une fois que nous avons terminé avec la boucle for
, cela affiche une nouvelle ligne.
Cet awk devrait fonctionner indépendamment de l'emplacement du champ entre guillemets et fonctionne également avec les guillemets échappés.
awk '{while(match($0,/"[^"]+",|([^,]+(,|$))/,a)){
$0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
print b[1] b[4];x=0}' file
"[email protected],www.example.com",field2,field3,field4
"[email protected]",field2,field3,field4
field1,"[email protected],www.example.com",field3,field4
"[email protected],www.example.com",field4
"[email protected]",field4
field1,field4
Cela fonctionne même sur
field1,"field,2","but this field has ""escaped"\" quotes",field4
Que la puissante variable FPAT échoue!
while(match($0,/"[^"]+",|([^,]+(,|$))/,a))
Démarre une boucle while qui continue tant que la correspondance est réussie (c'est-à-dire qu'il y a un champ).
La correspondance correspond à la première occurrence de l'expression régulière qui correspond incidemment aux champs et la stocke dans le tableau a
$0=substr($0,RSTART+RLENGTH);b[++x]=a[0]
Ensembles $0
pour commencer à la fin du champ correspondant et ajoute le champ correspondant à la position de tableau correspondante dans b
.
print b[1] b[4];x=0}
Imprime les champs souhaités à partir de b
et remet x à zéro pour la ligne suivante.
Échouera si le champ contient à la fois des guillemets d'échappement et une virgule
Mis à jour pour prendre en charge les champs vides
awk '{while(match($0,/("[^"]+",|[^,]*,|([^,]+$))/,a)){
$0=substr($0,RSTART+RLENGTH);b[++x]=a[0]}
print b[1] b[4];x=0}' file