2017-09-15 1 views
5

Je veux supprimer un motif avec sed, seulement à la deuxième occurrence. Voici ce que je veux, supprimer un motif mais sur la deuxième occurrence.Sed remplacer à la deuxième occurrence

Ce qui est dans le file.csv:

a,Name(null)abc.csv,c,d,Name(null)abc.csv,f 
a,Name(null)acb.csv,c,d,Name(null)acb.csv,f 
a,Name(null)cba.csv,c,d,Name(null)cba.csv,f 

sortie souhaitée:

a,Name(null)abc.csv,c,d,Name,f 
a,Name(null)acb.csv,c,d,Name,f 
a,Name(null)cba.csv,c,d,Name,f 

C'est ce que j'ai essayé:

sed -r 's/(\(null)\).*csv//' file.csv 

Le problème ici est que l'expression régulière est trop gourmand, mais je ne peux pas faire est d'arrêter. J'ai aussi essayé, de sauter la première occurrence de « null »:

sed -r '0,/null/! s/(\(null)\).*csv//' file.csv 

aussi essayé mais le regex gourmand est toujours le problème.

sed -r 's/(\(null)\).*csv//2' file.csv 

J'ai lu que ? peut faire la regex « paresseux », mais je ne peux pas faire l'entraînement.

sed -r 's/(\(null)\).*?csv//' file.csv 
+0

Si vous avez 3 '' (null) '' ou plus et que vous voulez toujours supprimer uniquement la 2ème occurrence, hink il serait plus facile de faire avec perl, en utilisant '. *?' au lieu de '. *'. –

Répondre

1

Le plus robuste awk solution:

fichier échantillon étendu input.csv:

12,Name(null)randomstuff.csv,2,3,Name(null)randomstuff.csv, false,Name(null)randomstuff.csv 
12,Name(null)AotherRandomStuff.csv,2,3,Name(null)AotherRandomStuff.csv, false,Name(null)randomstuff.csv 
12,Name(null)alphaNumRandom.csv,2,3,Name(null)alphaNumRandom.csv, false,Name(null)randomstuff.csv 

L'emploi:

awk -F, '{ c=0; for(i=1;i<=NF;i++) if($i~/\(null\)/ && c++==1) sub(/\(null\).*/,"",$i) }1' OFS=',' input.csv 

La sortie:

12,Name(null)randomstuff.csv,2,3,Name, false,Name(null)randomstuff.csv 
12,Name(null)AotherRandomStuff.csv,2,3,Name, false,Name(null)randomstuff.csv 
12,Name(null)alphaNumRandom.csv,2,3,Name, false,Name(null)randomstuff.csv 
+0

Super c'est ça fonctionne très bien! Je vais devoir vérifier plus sur l'outil awk! – BeGreen

4

sed ne fournit un moyen facile de spécifier quel match à remplacer. Il suffit d'ajouter le numéro après délimiteurs

$ sed 's/(null)[^.]*\.csv//2' ip.csv 
a,Name(null)abc.csv,c,d,Name,f 
a,Name(null)acb.csv,c,d,Name,f 
a,Name(null)cba.csv,c,d,Name,f 

$ # or [^,] if there are no , within fields 
$ sed 's/(null)[^,]*//2' ip.csv 
a,Name(null)abc.csv,c,d,Name,f 
a,Name(null)acb.csv,c,d,Name,f 
a,Name(null)cba.csv,c,d,Name,f 

De plus, pas besoin d'échapper à () lorsqu'ils ne sont pas en utilisant des expressions régulières étendues

+0

Je l'ai essayé si vous regardez de plus près dans mon message. Le problème était le Grege Regex. J'ai dû changer '. *' Avec '[^,] *' comme dans votre exemple. Je vous remercie. – BeGreen

+1

eh bien je n'ai pas remarqué que tu avais essayé // // 1 (plus tard édité à '// 2') ... donc tu n'as été repoussé que par un problème glouton ... facile à résoudre dans ce cas comme il y en a solutions de contournement avec '[^,]' ou '[.]' ... pour le cas générique, vous pourriez avoir besoin d'analyseurs csv appropriés disponibles dans perl/python/etc – Sundeep

+1

Vous avez raison, je pourrais de fait cela avec pyexcel que j'utilise dans mon script. N'a pas pensé à ça! – BeGreen

-1

Exécuter:

awk '{sub(/.null.....csv,f/,",f")}1' file 

Et la sortie doit être:

a,Name(null)abc.csv,c,d,Name,f 
a,Name(null)acb.csv,c,d,Name,f 
a,Name(null)cba.csv,c,d,Name,f