Extraire les données d'un fichier et les placer dans différents fichiers en fonction d'une valeur de colonne

14

Nous allons générer un fichier csv avec les valeurs ci-dessous

yp1234,577,1,3
yp5678,577,3,5
yp9012,132,8,9

J'ai besoin d'extraire des données et de créer des fichiers en fonction de la deuxième colonne. Si c'est 577, la ligne entière doit être extraite et placée dans un fichier séparé. Je veux dire que j'ai besoin d'un fichier ayant des lignes avec la deuxième colonne en tant que 577 seul et un autre fichier avec la deuxième colonne en tant que 132 seul

J'ai essayé d'utiliser IF mais je n'ai pas fonctionné

user3116123
la source
5
En fait, publier le code qui ne fonctionne pas est toujours une bonne idée.
goldilocks

Réponses:

27

Utilisation awk:

awk -F, '{ print > $2 ".csv" }' file.csv

Cela va créer les deux fichiers 577.csvet 132.csvdans votre répertoire actuel.

La commande ci-dessus suppose que vous ne pouvez avoir que 132ou 577comme deuxième champ. Il créera un nom de fichier pour chacune des valeurs trouvées dans le deuxième champ de l'ensemble file.csv.

S'il existe d'autres valeurs que les deux qui vous intéressent et que vous souhaitez ignorer ces lignes, procédez à la place:

awk -F, '$2 == "577" || $2 == "132" { print > $2 ".csv" }' file.csv
terdon
la source
1
Il existe des awkimplémentations de bogues qui ne peuvent pas être utilisées print > $2 ".cvs". Vous sur ceux -ci , doivent d' abord calculer le nom de fichier, puis procédez print: fname = $2 ".cvs"; print > fname.
Kusalananda
3

J'aime la awksolution de terdon , mais par souci d'exhaustivité, voici une suggestion utilisant uniquementbash

while IFS=, read -r a1 a2 a3 a4; do 
    echo "$a1,$a2,$a3,$a4" >> "$a2".csv
done < file.csv

Il produira des fichiers 577.csvet 132.csvdans le répertoire courant.

grebneke
la source
3

Pour extraire tous les 577 vers stdout

grep -e '^.*,577,.*,.*$' youfile.csv >result_extract_557.csv

- edit 1 Corrigé, basé sur le commentaire de @ terdon ci-dessous pour éviter les fausses correspondances quand au moins 3 virgules en ligne avec 577.

grep -e '^[:alnum:]*,577,[:digit:]*,[:digit:]*$' youfile.csv >result_extract_557.csv

Mais je pense que sa awksolution est plus complète.

X Tian
la source
Cela correspondra même si 577 se trouve sur un autre champ, pas sur le second ou s'il fait partie d'un champ. Par exemple foo577barou yp9012,132,8,577.
terdon
Je pensais que mes virgules rendraient la position du champ dépendante?
X Tian
Désolé, j'ai donné de mauvais exemples, mais ils .*peuvent également correspondre à des virgules, vous ne savez donc pas à quel champ vous correspondez. Pourrait être le deuxième, pourrait également être le 45e. Ma deuxième plainte était fausse, vous avez raison de dire que les virgules protègent contre les correspondances foo577bar.
terdon
que faire si | est utilisé à la place de,.
user3116123
réception de l'erreur ci-dessous grep: option illégale - e Utilisation: grep -hblcnsviw fichier de signatures. . .
user3116123
1

En utilisant csvkit:

$ csvgrep -c 2 -m 577 data.csv >output.csv

Les -c 2marques cvsgrepconsidèrent la deuxième colonne et -m 577nous lui demandons de faire correspondre la chaîne 577de cette colonne.

Ce qui suit sera écrit à output.csv:

yp1234,577,1,3
yp5678,577,3,5

Pour faire correspondre un certain nombre de chaînes et écrire la sortie dans un fichier pour chaque chaîne:

for pattern in 577 132; do
  csvgrep -c 2 -m "$pattern" data.csv >"output-$pattern.csv"
done

Cela créera les deux fichiers output-132.csvet output-577.csv.

Kusalananda
la source