Supprimer la ligne dans le fichier correspondant à une chaîne mais ne correspondant pas à une autre – SED, BASH?

Je veux supprimer toutes les lignes d’un fichier contenant le mot “test”, mais si cette ligne contient “test @”, je ne souhaite pas la supprimer.

Il y a probablement une manière géniale de le faire avec sed mais je me bats, j’ai essayé d’écrire une boucle de bash en utilisant sed mais c’est probablement stupide.

filetest=/tmp/filetest filetest_tmp=/tmp/filetest.tmp> $filetest_tmp fi done < $filetest cp $syslog_tmp $filetest 

Comme vous pouvez le constater, je suis un newb à ceci 🙁

 sed -e '/test/{/test@/!d;}' 

Le premier motif correspond aux lignes contenant «test»; le second motif supprime les lignes à moins qu’elles ne correspondent à «test @».

Testé sur le fichier de données:

 aaaa bbbtestbbb ccctest@ccc test! dddd 

Sortie:

 aaaa ccctest@ccc dddd 

Cela semble répondre à vos exigences.

Utilisez grep :

 grep -v 'test[^@]' infile 

En général, grep imprime les lignes correspondantes, mais -v indique d’imprimer des lignes non correspondantes.

L’expression régulière correspond à toute occurrence de “test” qui est suivie de tout sauf d’un “@”. Cela ne pose aucun problème si vous n’avez pas à vous attendre à un «test» à la fin d’une ligne. Si tel est le cas, utilisez

 grep -E -v 'test([^@]|$)' 

Je ne pense pas que cela vaille la peine de comprendre pourquoi votre solution ne fonctionne pas, car elle est brisée à bien des égards.

Si vous retournez votre question un peu, cela devient:

Comment filtrer toutes les lignes d’un fichier contenant la chaîne ‘test @’ ou ne contenant pas la chaîne ‘test’.

Cela peut par exemple se faire en awk comme ceci:

 awk '!/foo/ || /foo@/' testfile 

La réponse de Jonathan marche aussi, je voulais juste vous donner une version alternative.

Il n’y a pas besoin de fichier tmp si vous utilisez ed !

 # cf. http://wiki.bash-hackers.org/howto/edit-ed cat <<-'EOF' | ed -s file H ,g/test$/d ,g/test[^@]/d wq EOF