Grep et coupure d'une variable

eZula -  
jipicy Messages postés 41342 Statut Modérateur -
Bonjour,

Bonjour,

Dans un fichier a.txt :

--------------
%SystemRoot%\abcd?.exe
%SystemRoot%\abcd.exe
%SystemRoot%\abc?.exe
%SystemRoot%\abcd1.exe
%SystemRoot%\abcdkz.exe
%SystemRoot%\abcd???.exe
---------------

comment faire pour trouver toutes les lignes qui répondent exactement à ces 3 critères :
- commencent par %SystemRoot%\abc,
- suivi d'un unique caractère quelconque,
- et enfin de l'expression ".exe" ?

ceci pour arriver à afficher simplement :

-----------
%SystemRoot%\abcd.exe
%SystemRoot%\abc?.exe
----------

Bien sur j'ai essayé un grand nombre de combinaisons avec grep -n, egrep -n et fgrep (il me faut les numéros de ligne), mais cela ne donne rien de convaincant. De plus je suis sur un pb bien plus complexe mais je 'aperçois déjà que ça coince à ce niveau

Merci pour votre aide

PS : je signale par respect pour les intervenants que j'avais posté le même sujet ici https://www.developpez.net/forums/d518055/systemes/linux/shell-commandes-gnu/grep-expression-reguliere/#post3148329 mais que malheureusement depuis j'ai pas avancé d'un chouilla

17 réponses

jipicy Messages postés 41342 Statut Modérateur 4 896
 
Salut,
grep -En '^%SystemRoot%\\abc.?\.exe'
ou
egrep -n '^%SystemRoot%\\abc.?\.exe'
;-))
0
HostOfSeraphim Messages postés 7340 Statut Contributeur 1 608
 
J'ai pourtant l'impression que pour ce problème là particulièrement, tu avais réussi à avoir la bonne commande :

grep -n '^%SystemRoot%\\abc.\.exe' a.txt

Non ?

0
eZula
 
merci pour vos réponses. Mais le problème réel est que %SystemRoot%\abc n'est pas connu, il est récupéré comme variable $i par une boucle for. Ce fichier n'est qu'un échantillon

--------------
for i in $(grep '\.exe$' a.txt)
do echo `expr "$i" : "\(.*\)......$"` >> Exe.txt
done
-------------

donne le fichier Exe.txt :

---------------
%SystemRoot%\abcd
%SystemRoot%\abc
%SystemRoot%\abc
%SystemRoot%\abcd
%SystemRoot%\abcdk
%SystemRoot%\abcd??
-------------

puis

--------------
for i in $(uniq -d Exe.txt); do echo "Suggestion : "$i"?.exe" >> Doublons.txt; fgrep -n "$i" a.txt >> Doublons.txt; echo >> Doublons.txt; done
----------------

donne le fichier Doublons.txt

--------------
Suggestion : %SystemRoot%\abc?.exe
1:%SystemRoot%\abcd?.exe
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
4:%SystemRoot%\abcd1.exe
5:%SystemRoot%\abcdkz.exe
6:%SystemRoot%\abcd???.exe
--------------

et ce que je souhaite :

----------------
Suggestion : %SystemRoot%\abc?.exe
1:%SystemRoot%\abc?.exe
2:%SystemRoot%\abcd.exe
----------------

Désolé, j'aurais du donner le lien direct de la problématique majeure, https://www.developpez.net/forums/d518055/systemes/linux/shell-commandes-gnu/grep-expression-reguliere/#post3148049

le but est de voir si en retranchant les 4 derniers caractères de chaque ligne du fichier a.txt, on n'obtient pas de doublons. Il faut arriver à matcher toutes ces lignes exéctement.
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
Essaye ça :
grep -n "$(echo $i | sed 's/\\/\\\\/;s/.\./\.\\./')" a.txt
;-))
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
eZula
 
ça ne semble pas marcher, ai-je bien placé ta suggestion :

-----------------
for i in $(uniq -d Exe.txt); do echo "Suggestion : "$i"?.exe" >> Doublons.txt; grep -n "$(echo $i | sed 's/\\/\\\\/;s/.\./\.\\./')" a.txt ; done
-----------------

résultat :

-----------------
1:%SystemRoot%\abcd?.exe
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
4:%SystemRoot%\abcd1.exe
5:%SystemRoot%\abcdkz.exe
6:%SystemRoot%\abcd???.exe
---------------------

résultat attendu :

---------------------
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
---------------------
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
[jp@MDK-2008 trash]$ cat plop 
%SystemRoot%\abcd?.exe
%SystemRoot%\abcd.exe
%SystemRoot%\abc?.exe
%SystemRoot%\abcd1.exe
%SystemRoot%\abcdkz.exe
%SystemRoot%\abcd???.exe
 
[jp@MDK-2008 trash]$ var="%SystemRoot%\abc?.exe"
[jp@MDK-2008 trash]$ grep -n "$(echo $var | sed 's/\\/\\\\/;s/.\./\.\\./')" plop 
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
[jp@MDK-2008 trash]$
;-))
0
eZula
 
Ok, mais il y a deux éléments qui ne vont pas dans le contexte :

1. la "suggestion" n'est plus bonne :

---------------------
for i in $(uniq -d Exe.txt); do echo "Suggestion : "$i"?.exe" ; grep -n "$(echo $i | sed 's/\\/\\\\/;s/.\./\.\\./')" a.txt ; done
---------------------

---------------------
Suggestion : %SystemRoot%\ab?.exe
---------------------

il devrait écrire :

---------------------
Suggestion : %SystemRoot%\abc?.exe
---------------------

2. Je n'obtiens pas la liste des lignes correspondant exactement aux critères du problème :

---------------------
1:%SystemRoot%\abcd?.exe
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
4:%SystemRoot%\abcd1.exe
5:%SystemRoot%\abcdkz.exe
6:%SystemRoot%\abcd???.exe
---------------------

est-ce que tu arrives à obtenir ce résultat dans une boucle for ?
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
Ok, je crois que j'ai cerné le problème, en fait le "grep" doit se faire sur le fichier "Doublons.txt" :
[jp@MDK-2008 trash]$ cat Doublons.txt 
Suggestion : %SystemRoot%\abc?.exe
1:%SystemRoot%\abcd?.exe
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
4:%SystemRoot%\abcd1.exe
5:%SystemRoot%\abcdkz.exe
6:%SystemRoot%\abcd???.exe

[jp@MDK-2008 trash]$ grep "$(echo $var | sed 's/\\/\\\\/;s/.\./\.\\./')" Doublons.txt 
Suggestion : %SystemRoot%\abc?.exe
2:%SystemRoot%\abcd.exe
3:%SystemRoot%\abc?.exe
[jp@MDK-2008 trash]$ 
;-))
0
eZula
 
je ne suis pas sur d'être très clair dans mes explications, probablement à cause du fait que je tourne en rond depuis des semaines sur ce problème. Désolé, je reprends tout, n'hésitez pas s'il y a des points obscurs dans la formulation :

1. Nous avons un fichier a.txt dont chaque ligne représente le chemin d'un fichier/dossier windows, en voici un échantillon :

--------------
%SystemRoot%\abcd?.exe
%SystemRoot%\abcd.exe
%SystemRoot%\abc?.exe
%SystemRoot%\abcd1.exe
%SystemRoot%\abcdkz.exe
%SystemRoot%\abcd???.exe
%SystemDrivet%\abcd???.dll
--------------

Le problème à résoudre est le suivant : recherche des doublons .exe en amputant un caractère précédant l'expression .exe, et proposer une suggestion de remplacement

a) dans un premier temps, on isole tous les fichiers exe, càd toutes les lignes se terminant par l'expression .exe, on leur ampute l'expression ".exe" et un caractère supplémentaire, puis on redirige le résultat dans le fichier Exe.txt :

--------------
for i in $(grep '\.exe$' a.txt)
do echo `expr "$i" : "\(.*\).....$"` >> Exe.txt
done
--------------

b) une fois ce fichier Exe.txt obtenu :

--------------
%SystemRoot%\abcd
%SystemRoot%\abc
%SystemRoot%\abc
%SystemRoot%\abcd
%SystemRoot%\abcdk
%SystemRoot%\abcd??
--------------

=> on regarde s'il y a des doublons pour chaque ligne dans Exe.txt : si c'est bien le cas, alors il s'agit de rechercher dans le fichier d'origine a.txt les lignes où apparaissent exactement ces doublons, sachant qu'ils ne devront être précédés que d'un caractère quelconque, suivi de l'expression .exe, et en affichant la suggestion de substitution juste au-dessus :

par exemple, dans le fichier Exe.txt, les deux lignes

--------------
%SystemRoot%\abc
%SystemRoot%\abc
--------------

constiutent un doublon, il faut donc rechercher l'expression %SystemRoot%\abc + un caractère quelconque + l'expression .exe dans a.txt, et afficher les n° de ligne correspondants.

--------------
for i in $(uniq -d Exe.txt); do echo "Suggestion : "$i"?.exe" ; grep -n "$(echo $i | sed 's/\\/\\\\/;s/.\./\.\\./')" a.txt ; done
--------------

Le résultat souhaité serait donc, avec notre échantillon :

--------------
Suggestion :%SystemRoot%\abc?.exe
2: %SystemRoot%\abcd.exe
3: %SystemRoot%\abc?.exe
--------------

c'est important de rechercher ces doublons dans le fichier d'origine, car c'est dans ce dernier que vont s'opérer les substitutions (c'est aussi pour cela que j'utilise grep, pour avoir les n° de ligne avec l'option -n)
0
eZula
 
Bon, je pense avoir trouvé un début de solution, grâce à ta pise ; il était en effet nécessaire de substituer les \ par des \\ pour qu'ils passent correctement dans grep

_____________________
for i in $(grep '\.exe.$' a.txt)
do echo `expr "$i" : "\(.*\)......$"` >> Exe.txt
done

Ext=\.exe

for i in $(uniq -d Exe.txt)
do echo "=> Suggestion : "$i"?.exe" >> Doublons.txt
a=$(echo $i | sed 's/\\/\\\\/g')
egrep -n ^"$a.$Ext".$ a.txt >> Doublons.txt
done
____________________

ça a l'air de fonctionner. Propre ou pas propre, selon toi ?
En jouant sur les . de `expr "$i" : "\(.*\)......$"` il sera possible de jouer sur la profondeur de recherche afin de déterminer s'il n'y a pas encore des doublons en amputant n caractères en deça de l'expression .exe

Juste un dernier truc que je pige pas, si je fais :

egrep -n ^"$a.$Ext"$ a.txt >> Doublons.txt

ça ne marche pas. En ajoutant un . ou même .$ ça marche. Pourtant, après l'expression .exe, il n'y a rien, c'est la fin de la ligne et il n'y a pas d'espace ou de tabulation en fin de ligne. Comment expliquer ça ?

Merci
0
eZula Messages postés 3509 Statut Contributeur 392
 
Salut,

je suis sur un problème à peu près similaire, qui consiste, dans un fichier a.txt à :

1. isoler les dossiers (càd grossièrement les lignes qui ne contiennent pas de .)
2. pour chaque ligne du fichier a.txt, supprimer les lignes qui commencent par ces chemins de dossiers, mais qui incluent des sous-éléments

Voici le fichier :

cat a.txt
%AppData%\addon.dat
%AppData%\addon.dat
%AppData%\inside.exe
%AppData%\Microsoft\Windows\fkoym.exe
%AppData%\Microsoft\Windows\qganni.exe
%AppData%\Microsoft\Windows\vvpmyvaw.exe
%AppData%\SpeedRunner
%AppData%\SpeedRunner\config.cfg
%AppData%\SpeedRunner\SRUninstall.exe
%AppData%\WinTouch
%AppData%\WinTouch\wintouch.cfg
%AppData%\WinTouch\WinTouch.exe
%AppData%\WinTouch\WTUninstaller.exe


le but est donc d'éliminer ces lignes puisqu'elles représentent des sous-éléments de dossiers (%AppData%\SpeedRunner et %AppData%\WinTouch) :

%AppData%\SpeedRunner\config.cfg
%AppData%\SpeedRunner\SRUninstall.exe
%AppData%\WinTouch\wintouch.cfg
%AppData%\WinTouch\WinTouch.exe
%AppData%\WinTouch\WTUninstaller.exe


Voici l'une de mes centaines de tentatives :

for i in "$(egrep -v "\." a.txt)" ; do a="$(echo $i | sed 's/\\/\\\\/;s/.\./\.\\./')" ; cat a.txt | sed -e 's/$a.*$//g' ; done


évidemment ça ne marche pas, est-ce que quelqu'un aurait une piste supplémentaire. Attention, c'est encore un échantillon et les lignes peuvent contenir des espaces

Merci bien
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
Salut,
[jp@MDK-2008 trash]$ cat a.txt
%AppData%\addon.dat
%AppData%\addon.dat
%AppData%\inside.exe
%AppData%\Microsoft\Windows\fkoym.exe
%AppData%\Microsoft\Windows\qganni.exe
%AppData%\Microsoft\Windows\vvpmyvaw.exe
%AppData%\SpeedRunner
%AppData%\SpeedRunner\config.cfg
%AppData%\SpeedRunner\SRUninstall.exe
%AppData%\WinTouch
%AppData%\WinTouch\wintouch.cfg
%AppData%\WinTouch\WinTouch.exe
%AppData%\WinTouch\WTUninstaller.exe

[jp@MDK-2008 trash]$ cat foo.sh

#! /bin/bash

for line in $(grep -v '\.' a.txt)
do
        sed -i -r '/'"${line/\\/\\\\}"'.+/d' a.txt
done

[jp@MDK-2008 trash]$ ./foo.sh
[jp@MDK-2008 trash]$ cat a.txt
%AppData%\addon.dat
%AppData%\addon.dat
%AppData%\inside.exe
%AppData%\Microsoft\Windows\fkoym.exe
%AppData%\Microsoft\Windows\qganni.exe
%AppData%\Microsoft\Windows\vvpmyvaw.exe
%AppData%\SpeedRunner
%AppData%\WinTouch

[jp@MDK-2008 trash]$
;-))
0
eZula Messages postés 3509 Statut Contributeur 392
 
Ok merci pour cette approche différente. Par contre pour conserver tel quel a.txt et rediriger le résultat dans un fichier u.txt comment faire?
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
C’est là que le bât blesse ;-(

Les modifications du fichier doivent être dynamique. Donc seule solution faire une copie du fichier original avant et travailler sur la copie...
0
eZula Messages postés 3509 Statut Contributeur 392
 
Bon, d'accord.

Par contre et par curiosité, qu'est-ce que c'est qui n'allait pas avec la méthode :

for i in "$(egrep -v "\." a.txt)" ; do a="$(echo $i | sed 's/\\/\\\\/;s/.\./\.\\./')" ; cat a.txt | sed -e 's/$a.*$//g' ; done
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
Les guillemets autour de l'expression qui rassemblent tout dans une seule et même variable (à enlever donc) :
[jp@MDK-2008 trash]$ for i in "$(egrep -v "\." a.txt)" ; do echo $i;done
%AppData%\SpeedRunner %AppData%\WinTouch

[jp@MDK-2008 trash]$ for i in $(egrep -v "\." a.txt) ; do echo $i;done
%AppData%\SpeedRunner
%AppData%\WinTouch

Puis les quotes simples dans l'expression avec "sed" qui empêchent l'évaluation de la variable :
sed -e 's/$a.*$//g'

à remplacer par des guillemets pour que la variable "$a" soit évaluée :
sed -e "s/$a.*$//g"


Ton script aurait du ressembler à ça :
for i in $(egrep -v "\." a.txt); do a=$(echo "$i" | sed 's/\\/\\\\/;s/.\./\.\\./'); cat a.txt | sed -e "s/$a.*$//g"; done

Mais même comme ça on retombe dans ce que j'ai essayé de t'expliquer au-dessus, il faut que "sed" agisse dynamiquement sur le fichier sinon on a un double affichage (un par variable traitée) :
$ for i in $(egrep -v "\." a.txt); do a=$(echo "$i" | sed 's/\\/\\\\/;s/.\./\.\\./'); cat a.txt | sed -e "s/$a.*$//g"; done
%AppData%\addon.dat
%AppData%\addon.dat
%AppData%\inside.exe
%AppData%\Microsoft\Windows\fkoym.exe
%AppData%\Microsoft\Windows\qganni.exe
%AppData%\Microsoft\Windows\vvpmyvaw.exe

%AppData%\WinTouch
%AppData%\addon.dat
%AppData%\addon.dat
%AppData%\inside.exe
%AppData%\Microsoft\Windows\fkoym.exe
%AppData%\Microsoft\Windows\qganni.exe
%AppData%\Microsoft\Windows\vvpmyvaw.exe
%AppData%\SpeedRunner
0
eZula Messages postés 3509 Statut Contributeur 392
 
bon, en testant la même commande sur le fichier entier - qui contient des chemins de fichiers/dossiers comme précisé plus haut - j'obtiens deux erreurs actuellement

1. la première, c'est :

sed: -e expression n°1, caractère 55: Référence arrière invalide


conséquence : rien n'est supprimé

2. La deuxième, en ajoutant simplement ces deux chemins au fichier échantillon a.txt de tout à l'heure:

%ProgramFiles%\Microsoft Update
%ProgramFiles%\Microsoft Update\abc.txt


la commande efface les deux lignes, et non pas uniquement la deuxième

D'où peut venir le pb ?
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
j'obtiens deux erreurs actuellement
1. la première, c'est :
sed: -e expression n°1, caractère 55: Référence arrière invalide


Il me faut le fichier de référence ainsi que la syntaxe que tu emploies, sans quoi je pédale dans la choucroute ;-((

Concernant le 2nd point, rajoute ça dans le script :
#! /bin/bash

IFS=$'\n'
for line in $(grep -v '\.' a.txt)
do
        sed -i -r '/'"${line/\\/\\\\}"'.+/d' a.txt
done
et ça devrait rouler, du moins chez moi ça le fait ;-))
0
eZula Messages postés 3509 Statut Contributeur 392
 
Ok, tu as raison IFS=$'\n' règle bien le problème n°2

Concernant le 1, désolé effectivement sans le fichier c'est pas bien, par contre il fait plus de 3000 lignes, je te mets un lien si tu es ok http://www.alt-shift-return.org/Info/Fichiers/Temp/Coucou.txt.zip
La commande utilisée est celle que tu as suggéré, dans un terminal

for line in $(grep -v '\.' a.txt)
do
        sed -i -r '/'"${line/\\/\\\\}"'.+/d' a.txt
done
0
jipicy Messages postés 41342 Statut Modérateur 4 896
 
Bon effectivement, dans la mesure où il y a aussi plusieurs anti-slash à protéger il faut rajouter un slash dans l'expansion de la variable :
${line//\\/\\\\}
Puis il m'a fallu convertir le fichier original (Coucou.txt) au format Unix (avec la commande dos2unix) et à partir de là, le script roule tout seul ;-))
0