J'ai un très gros fichier csv. Comment supprimer le dernier ,
avec sed (ou similaire)?
...
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0],
]
Sortie désirée
...
[11911,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11912,0,"BUILDER","2014-10-15","BUILDER",0,0],
[11913,0,"BUILDER","2014-10-15","BUILDER",0,0]
]
La commande sed suivante supprimera la dernière occurrence par ligne, mais je veux par fichier.
sed -e 's/,$//' foo.csv
Cela ne fonctionne pas non plus
sed '$s/,//' foo.csv
Réponses:
En utilisant
awk
Si la virgule est toujours à la fin de l'avant-dernière ligne:
Utilisation de
awk
etbash
En utilisant
sed
Pour OSX et autres plates-formes BSD, essayez:
En utilisant
bash
la source
sed: 1: "x;${s/,$//;p;x}; 2,$ p": extra characters at the end of x command
sed
et il est souvent différent de manière subtile. Je n'ai pas accès à OSX pour tester cela, mais veuillez essayersed -n -e x -e '${s/,$//;p;x;}' -e '2,$ p' input
Vous pouvez simplement essayer la commande Perl one-liner ci-dessous.
Explication:
,
Correspond à une virgule.(?!.*,)
La recherche d'anticipation négative affirme qu'il n'y aurait pas de virgule après cette virgule correspondante. Cela correspondrait donc à la dernière virgule.s
Et le plus important est les
modificateur DOTALL qui fait que le point correspond également aux caractères de nouvelle ligne.la source
perl -0777 -pi -e 's/(.*),(.*?)/\1\2/s'
. Cela fonctionne parce que le premier.*
est gourmand, tandis que le second ne l'est pas.Cela ne devrait supprimer que la dernière occurrence d'un
,
dans n'importe quel fichier d'entrée - et il imprimera toujours ceux dans lesquels un,
ne se produit pas. Fondamentalement, il met en mémoire tampon des séquences de lignes qui ne contiennent pas de virgule.Quand il rencontre une virgule, il échange la mémoire tampon de ligne actuelle avec la mémoire tampon de maintien et de cette manière imprime simultanément toutes les lignes qui se sont produites depuis la dernière virgule et libère sa mémoire tampon de conservation.
Je creusais simplement mon fichier historique et j'ai trouvé ceci:
C'est en fait assez bon. Oui, il utilise
eval
, mais il ne lui passe jamais rien au-delà d'une référence numérique à ses arguments. Il construit dessed
scripts arbitraires pour gérer une dernière correspondance. Je vais te montrer:Cela imprime ce qui suit à stderr. Ceci est une copie de
lmatch
l'entrée de:Le
eval
sous-shell ed de la fonction parcourt une fois tous ses arguments. En les parcourant, il itère un compteur de manière appropriée en fonction du contexte de chaque commutateur et ignore autant d'arguments pour la prochaine itération. À partir de là, cela fait l'une des quelques choses par argument:$a
à$o
.$a
est attribué en fonction de la valeur$i
qui est incrémentée par le nombre d'arguments pour chaque arg traité.$a
se voit attribuer l'une des deux valeurs suivantes:a=$((i+=1))
- ceci est attribué si une option courte n'a pas d'argument ajouté ou si l'option était longue.a=$i#-?
- ceci est attribué si l'option est courte et que son argument lui est ajouté.a=\${$a}${1:+$d\${$(($1))\}}
- Indépendamment de l'affectation initiale,$a
la valeur de est toujours entourée d'accolades et - dans un-s
cas -$i
est parfois incrémentée de plus et un champ supplémentaire délimité est ajouté.Le résultat est qu'on
eval
ne passe jamais une chaîne contenant des inconnues. Chacun des arguments de ligne de commande est référencé par son numéro d'argument numérique - même le délimiteur qui est extrait du premier caractère du premier argument et est la seule fois où vous devez utiliser le caractère non échappé. Fondamentalement, la fonction est un générateur de macros - elle n'interprète jamais les valeurs des arguments d'une manière spéciale car ellesed
peut (et le fera, bien sûr) facilement gérer cela lorsqu'elle analyse le script. Au lieu de cela, il organise simplement judicieusement ses arguments dans un script réalisable.Voici une sortie de débogage de la fonction au travail:
Et
lmatch
peut donc être utilisé pour appliquer facilement des expressions rationnelles aux données après la dernière correspondance dans un fichier. Le résultat de la commande que j'ai exécutée ci-dessus est:... qui, étant donné le sous-ensemble de l'entrée de fichier qui suit la dernière mise en
/^.0/
correspondance, applique les substitutions suivantes:sdd&&&&d
- se remplace$match
par lui-même 4 fois.sd'dsqd4
- le quatrième guillemet simple suivant le début de la ligne depuis le dernier match.sd"d\dqd2
- idem, mais pour les guillemets doubles et globalement.Et donc, pour montrer comment on pourrait utiliser
lmatch
pour supprimer la dernière virgule d'un fichier:PRODUCTION:
la source
-m
option et l' ai rendue obligatoire, je suis passée à plusieurs arguments pour re et repl pour-s
et j'ai également implémenté une gestion correcte du délimiteur. Je pense que c'est pare-balles. J'ai utilisé avec succès un espace et une seule citation comme délimiteur,Si la virgule n'est peut-être pas sur l'avant-dernière ligne
Utilisation de
awk
ettac
:La
awk
commande est simple pour effectuer la substitution la première fois que le motif est vu.tac
inverse l'ordre des lignes du fichier, laawk
commande finit donc par supprimer la dernière virgule.On m'a dit que
peut être plus efficace.
la source
Si vous pouvez utiliser
tac
:la source
voir /programming/12390134/remove-comma-from-last-line
Cela fonctionne pour moi:
Ma meilleure façon est de supprimer la dernière ligne et après avoir supprimé la virgule, ajoutez à nouveau le] char
la source
Essayez avec ci
vi
- dessous :Explication:
$-1
sélectionner l'avant-dernière lignes
remplacer\(,\)\(\_s*]\)
trouver une virgule suivie]
et séparée par des espaces ou une nouvelle ligne\2
remplacer par\(\_s*]\)
ex. espaces ou nouvelle ligne suivi de]
la source
Essayez avec la
sed
commande ci-dessous .la source