Recherche d'une chaine de caractère.

Fermé
rider641 Messages postés 8 Date d'inscription lundi 7 février 2011 Statut Membre Dernière intervention 8 février 2011 - 7 févr. 2011 à 21:57
mamiemando Messages postés 33274 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 septembre 2024 - 9 févr. 2011 à 08:56
Bonjour,

Je suis en BTS d'info et je me casse la tête sur un petit problème de devoir :

J'ai obtenu la commande suivante :

ls -li /usr/bin | grep "2 root" | sort -n

elle permet d'afficher les fichiers ayant 2 liens dans l'ordre croissant de leurs inodes.

Ne me demandez pas pourquoi j'utilise (grep "2 root") quand il y a un simple (find -links 2), c'est la condition initial du prof.

La suite de cet exo est un peux plus coriace à mon gout :
Il faut COMPLETER la ligne de commande précédente pour n'afficher, parmi ceux-ci, que les fichiers qui contiennent la chaîne de caractère "kill" (et bien sur toujours dans l'ordre croissant d'inodes!).

J'ai tout de suite penser à la commande

find ./ -type f -exec grep -Hn "kill" {} \;

Sauf que je n'arrive pas à faire le liens entre le résultat obtenu et la commande find.
J'ai essayé le "pipe" avec le "xargs" - rein à faire j'ai le message d'erreur.

Si non j'ai une autre astuce :

find /usr/bin -type f -links 2 -exec grep -Hn "kill" {} \;

Sauf que j'obtiens une simple arborescence de fichier, sans les numéros d'inodes et bien sur pas dans l'ordre croissant. Sans parler du fait que j'ai complétement CASSE la ligne de commande originale.

SVP aider moi .... si non dans 2 jours j'ai plus de cheveux sur ma tête.

Merci d'avance à celui qui prendra le temps d'éclairer ma lanterne.

A bientôt.
A voir également:

4 réponses

mamiemando Messages postés 33274 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 septembre 2024 7 783
7 févr. 2011 à 22:20
Non il faut simplement rajouter | grep "kill" derrière. Enfin si j'ai bien compris l'exercice. À mon avis tu n'as pas bien compris comment fonctionnait l'opérateur |.

Concrètement un processus a :
- un entrée (par défaut l'entrée standard, /dev/stdin, qui revient à lire la saisie clavier)
- une sortie quand tout va bien, numérotée "1" (la sortie standard, /dev/stdout, qui revient à écrire sur la console)
- une sortie quand ça va mal, numérotée "2" (la sortie d'erreur standard, /dev/stderr, qui revient également à écrire sur la console).

Quand un processus écrit sur la sortie 1 ou 2, il émet un flux texte. Ce flux peut ne pas être redirigé (auquel cas il apparaît dans la console), ou bien... être redirigé avec un opérateur shell :
- vers un fichier : opérateurs 1>, 1>> (notés aussi > et >>) pour les redirections sur la sortie 1, opérateurs 2> et 2>> pour la sortie 2,
- vers l'entrée standard d'un autre processus grâce à un pipe (tube), symbolisé par l'opérateur | : cette opérateur redirige le flux émis dans la sortie 1 vers l'entrée du processus qui suit.

Ainsi :

ls -1 /


... émet un flux texte vers /dev/stdout (sortie standard). La commande grep lit par défaut sur l'entrée standard (/dev/stdin). Il se met en attente jusqu'à arriver en fin de fichier (ou être interrompu). Il restitue sur la sortie 1 uniquement les lignes qui contiennent le motif qui lui est passé en paramètre. Ainsi cette commande :

ls -1 / | grep "s"


... injecte dans grep le flux émis par ls -1 /. Tout se passe comme si on tapait au clavier chaque ligne émise par ls -1 /. Du coup, grep ne transmet sur sa sortie 1 que les lignes qu'il lit contenant la lettre s. Ainsi cette commande liste les répertoires de / qui contiennent la lettre s.

Même principe pour la commande wc -l. Elle mouline un flux texte qui arrive sur /dev/stdin, compte le nombre de ligne totale, et l'écrit sur /dev/stdout :

ls -1 / | grep "s" | wc -l


Ainsi cette commande compte le nombre de répertoire de / contenant un s. Ton exercice fonctionne sur le même principe. Il consiste à générer un flux texte initial grâce à la commande ls et à n'en conserver que les bons morceaux. La commande qui initie le flux texte n'est pas forcément ls. Exemple :

netstat -ntlp | grep ":22"


... liste parmi les sockets ouvertes celle associée au port 22 (:22).

Une fois ton flux texte généré, rien n'empêche de l'injecter dans une commande. Exemple (sous debian/ubuntu) :

dpkg -l | grep "^rc" | cut -d" " -f3 | xarg sudo dpkg --purge


... supprime parmi les paquets installés/partiellement installés ceux dans l'état rc (la ligne commence alors par "rc", ce qui se note "^rc"), extrait la colonne contenant le nom du paquet (cut), remet ce flux horizontal (xargs) et l'injecte dans la commande sudo dpkg --purge.

Bref. C'est un bel outil :-)
1
stephane_mc2004 Messages postés 755 Date d'inscription samedi 12 juillet 2008 Statut Membre Dernière intervention 8 février 2011 96
Modifié par moska le 4/04/2011 à 00:14
Bonjour,
Il n'y a quelque chose que je ne comprends pas dans ton exo : le "2 root" . Il est obligatoire ?
**Ton astuce est très bien pensée :
Si non j'ai une autre astuce :

find /usr/bin -type f -links 2 -exec grep -Hn "kill" {} \;


Sauf que ce qu'elle fait (plutot ce qu'elle est sensée faire), c'est : trouver les fichiers de /usr/bin , qui ont 2 liens, et qui contiennent "kill".


Et vu que tu ne dois pas "casser" la commande originale, je suppose que tous les fichiers trouvés doivent avoir ce "2 root"..Non ?
Donc si c'est le cas, je crois avoir la solution à ton problème :)



Alors explications :
On a au départ : ls -li /usr/bin/ | grep "2 root" | sort -n
Cette instruction donne les fichiers de /usr/bin ayant deux liens, dans l'ordre croissant de leur inode. Bien.

Le résultat d'une telle commande donne chez moi :
143 -rwsr-xr-x 2 root root 123504 2011-01-19 19:01 sudo
143 -rwsr-xr-x 2 root root 123504 2011-01-19 19:01 sudoedit



Ce qui nous intéresse, ce sont les fichiers qui sont à droite, pas ce qui est à gauche (si j'ai bien compris) . Donc il va falloir extraire de ce résultat, la dernière partie. Comment faire ?
Il existe une commande, sed, qui te facilite cela. sed utiise des expressions régulières pour la recherche/suppression/modification de textes.
*-----------------Petit rappel de sed ----------------------------------------------*
syntaxe : sed -r -n -e 'COMMANDE_SED' [FICHIER]
-r : active les expressions régulières avancées
-n : lui dit de ne pas afficher le resultat dans la sortie standard (terminal)
-e : indique qu'il va falloir Exécuter la suite d'instruction sed qui suit le -e.

FICHIER : Optionnel. C'est le fichier dans lequel il faut faire les recherches/modif et tout. S'il n'est pas présent sur la ligne de commande, c'est l'entrée standard qui est alors utilisée. Ca tombe bien, car lorsqu'on utilise les tubes "|" (ou pipes en anglais ) , c'est la sortie standard de la commande à gauche du "|" qui est donnée à l'entrée standard de la commande à droite de "|" .

COMMANDE_SED : une commande que va exécuter sed. ce qui nous intéresse ici c'est la commande de substitution, qui s'écrit de la forme :
s/motif/remplacement/p
s : commande qui dit a sed : je veux faire des substitutions
motif : une expression régulière, qui décrit ce que tu cherches
remplacement : ce qui sera remplacé dans le motif trouvé
p : (print) on affiche les résultats des remplacements.

Les slashes "/" sont juste des séparateurs. Ils peuvent être n'importe quel caractère non-alphanumérique et non spéciaux pour les expressions reg. (comme / , # , %, ... )


Exemple : echo "je veux dormir" | sed -rne 's/dormir/manger/p'
Résultat : je veux manger

Exemple2 : supprimer tous les espaces
echo "je veux dormir" | sed -rne 's/\s//p'
\s signifie "espace" (space)
Résultat : jeveuxdormir


Exemple2 : inverser la jour et le mois :
echo "January 15" | sed -rne 's/([a-zA-Z])+ ([0-9][0-9])'/\2 \1/p'
Result. : 15 January


\1 = première parenthèse capturée
\2 = deuxième parenthèse capturée.



Le fait d'écrire \2 \1 dans la partie remplacement, mettra le contenu de la 2eme parenthèse AVANT celui de la 1ere, d'où l'inversion réalisée.
******************************************************

Donc revenons au problème. J'avais ça comme résultat de la première commande ls -li /usr/bin/ | grep "2 root" | sort -n :
143 -rwsr-xr-x 2 root root 123504 2011-01-19 19:01 sudo
143 -rwsr-xr-x 2 root root 123504 2011-01-19 19:01 sudoedit


. On va donner ce résult à sed, et extraire toute la partie de gauche. Je me suis donc basé sur la recherche de l'heure de modification (ici 19:01) puis la prise de ce qui est à droite de cette heure là :

sed -rne 's#.*([0-9][0-9]:[0-9][0-9])\s*(.+)$#\2#p'
Cette expression recherche toutes les lignes contenant des chiffres du type xx:xx (donc une heure), suivie d'un espace \s, puis du nom de fichier .+ (au moins un caractère), puis la fin de ligne $ (en fait c'est presque la syntaxe de mon résultat de la commande précédente)

Je remplace ce résultat par le contenu de la 2eme parenthèse (.+) (qui est pour moi, celle du nom du fichier). D'ou le \2.
La suite de commande jusque là est donc:

ls -li /usr/bin/ | grep "2 root" | sort -n | sed -rne 's#.*([0-9][0-9]:[0-9][0-9])\s*(.+)$#\2#p'

Résultat :
sudo
sudoedit

Le problème est que si je passe ces fichiers à grep, grep les fera par rapport au chemin relatif (pensera que ces 2 fichiers sont dans le dossier courant), or on veut bien qu'il les considère comme dans le dossier /usr/bin.
On a donc juste à changer le sed
sed -rne 's#.*([0-9][0-9]:[0-9][0-9])\s*(.+)$#/usr/bin/\2#p'

COmmande presque finale :
ls -li /usr/bin/ | grep "2 root" | sort -n | sed -rne 's#.*([0-9][0-9]:[0-9][0-9])\s*(.+)$#/usr/bin/\2#p'

Qui donne :

/usr/bin/sudo
/usr/bin/sudoedit

. Il reste enfin à passer CHACUN de ses fichiers à grep. Si on fait directement un grep, grep va penser que le texte à analyser est
/usr/bin/sudo
/usr/bin/sudoedit

, or ce n'est pas ce qu'on veut, mais plutot considérer que chaque ligne est un fichier dans lequel grep doit faire sa recherche. D'où xargs :)
Exemple : echo "fichier" | grep kill
Grep cherchera dans le TEXTE "fichier", le mot kill.

Exemple2 : echo "fichier" | xargs grep kill
Grep cherchera dans le fichier "fichier", le mot kill. Equivalent à grep kill fichier
En fait, xargs ne fait rien d'autre que rajouter un mot (reçu en entrée standard) à la ligne de commande de la commande qu'on veut exécuter.
echo . | xargs ls
Equivalent à ls .

Bref.
Commande finale :
ls -li /usr/bin/ | grep "2 root" | sort -n | sed -rne 's#.*([0-9][0-9]:[0-9][0-9])\s*(.+)$#/usr/bin/\2#p' | xargs grep -H kill


Bon courage :)

PS:
Chez moi, ça donne ça :
Fichier binaire /usr/bin/sudo concordant
Fichier binaire /usr/bin/sudoedit concordant


Si tu ne veux que récupérer le nom du fichier, encore à donner à un sed :)

ls -li /usr/bin/ | grep "2 root" | sort -n | sed -rne 's#.*([0-9][0-9]:[0-9][0-9])\s*(.+)$#/usr/bin/\2#p' | xargs grep -H kill | sed -rne 's#^.*(/usr/bin/.+)\s+(.+)#\1#p'

1
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 415
8 févr. 2011 à 07:40
Salut,

Et si on simplifiait le tout ?

ls -li /usr/bin/ | sort -n | awk '/2 root/ { print $NF }'


;-))
0
rider641 Messages postés 8 Date d'inscription lundi 7 février 2011 Statut Membre Dernière intervention 8 février 2011
7 févr. 2011 à 22:38
Salut, merci pour ta réponse SI COMPLÈTE !

Effectivement ça m'a éclairci des zones d'ombre .... cependant (désolé je suis blond :-)) je suis toujours pas arrivé.

J'ai fait :

ls -l /usr/bin | grep "2 root" | grep "kill"

Rien :-(

J'ai même essayé "NAME" (car je sais que cette chaîne de caractère est bien présente au moins dans un des fichiers) - et rien non plus!

Je comprends très bien le fonctionnement du "pipe" et des flux de données sur les différentes entrée/sortie, mais là, bizarrement, le lient ne se fait pas.

Des suggestion?

Merci quand même pour ta réponse détaillée.

Bonne soirée.
0
rider641 Messages postés 8 Date d'inscription lundi 7 février 2011 Statut Membre Dernière intervention 8 février 2011
8 févr. 2011 à 10:11
Bonjour,

Maintenant je suis vraiment certain - LES DIEUX DE L'INFORMATIQUE EXISTENT ! :-)))

Pour pondre de telles listes de commandes ... moi je dis chapeau.
Merci mille fois pour votre participation!

stephane_mc2004, merci, j'ai essayé ton code et, malheureusement, je n'obtiens pas le résultat attendu... afin bref ... pourtant la piste est bonne et je pense que je vais un peux triturer ce "sed" :-)

zip31 - merci également, mais j'ai déjà essayé une commande semblable.

Je pense surtout que je n'ai pas bien expliqué le sujet.

Alors je recommence :

On part, donc, de la ligne de commande :

ls -li /usr/bin | grep "2 root" | sort -n

Le résultat de cette commande est le suivant :


276928 -rwxr-xr-x 2 root root 1253828 aoû 29 2009 perl
276928 -rwxr-xr-x 2 root root 1253828 aoû 29 2009 perl15.10.0
278701 -rwxr-xr-x 2 root root 36601 aoû 29 2009 c2ph
278701 -rwxr-xr-x 2 root root 36601 aoû 29 2009 pstruct
278707 -rwxr-xr-x 2 root root 53325 aoû 29 2009 psed
278707 -rwxr-xr-x 2 root root 53325 aoû 29 2009 s2p



On a bien classé les fichiers qui ont 2 liens (c'est pour ça le grep "2 root" - je sais c'est barbare, il y a un simple find -links 2, mais bon ce sont les conditions du prof :-)) par ordre croissant de leurs inods : sort -n.

Maintenant il faut COMPLETER la ligne de commande (ls -li /usr/bin | grep "2 root" | sort -n) afin de RECHERCHER DANS LES FICHIERS QUI SONT A DROITE (perl, perl15.10.0, c2ph, pstruct, psed, s2p) CEUX QUI CONTIENNENT LA CHAINE DE CARACTERE {kill}.

Et puis il faut afficher le résultat dans le même ordre croissant. En fait, en supposant, par exemple, que les fichiers c2ph et psed contiennent un mot "kill" on doit obtenir le résultat suivant :

278701 -rwxr-xr-x 2 root root 36601 aoû 29 2009 c2ph
278707 -rwxr-xr-x 2 root root 53325 aoû 29 2009 psed


Voila en gros.
Et encore un GRAND MERCI !
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 415
8 févr. 2011 à 10:23
Re-

Et comme ça, c'est mieux ? ;-))

$ ls -li /usr/bin | grep "2 root" | sort -n
133276 -rwxr-xr-x 2 root   root        45192 2010-06-11 19:13 perlbug*
133276 -rwxr-xr-x 2 root   root        45192 2010-06-11 19:13 perlthanks*
135128 -rwxr-xr-x 2 root   root        12728 2009-05-28 20:38 skill*
135128 -rwxr-xr-x 2 root   root        12728 2009-05-28 20:38 snice*
135129 -rwxr-xr-x 2 root   root        13116 2009-05-28 20:38 pgrep*
135129 -rwxr-xr-x 2 root   root        13116 2009-05-28 20:38 pkill*
141198 -rwxr-xr-x 2 root   root         5440 2010-10-29 14:25 python*
141198 -rwxr-xr-x 2 root   root         5440 2010-10-29 14:25 python2.6*
152795 ---s--x--x 2 root   root       185916 2011-01-21 14:58 sudo*
152795 ---s--x--x 2 root   root       185916 2011-01-21 14:58 sudoedit*
279983 drwxr-xr-x 2 root   root         4096 2010-12-30 14:12 multiarch-i386-linux/

$ ls -li /usr/bin | grep  "2 root.*kill*" | sort -n
135128 -rwxr-xr-x 2 root   root        12728 2009-05-28 20:38 skill*
135129 -rwxr-xr-x 2 root   root        13116 2009-05-28 20:38 pkill*

$
0
rider641 Messages postés 8 Date d'inscription lundi 7 février 2011 Statut Membre Dernière intervention 8 février 2011
8 févr. 2011 à 12:07
Re,

Dans cette exemple tu as isolé les fichiers qui ont le NOM qui COMPORTE "kill".
Or je cherche les fichiers qui ont la chaine de caractère "kill" dans leurs CONTENU.

Par exemple, je dois trouver un fichier dont le contenu est :

$ less "nomDeFichier"

...................
....................
........ kill ...........
.............................
...........................

$ _


Aurais-tu une solution à ce problème?

Merci beaucoup.
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 415
8 févr. 2011 à 12:31
J'ai bien une solution, mais ça passe par une boucle while... ;-\

C'est bon quand même ?
0
rider641 Messages postés 8 Date d'inscription lundi 7 février 2011 Statut Membre Dernière intervention 8 février 2011
8 févr. 2011 à 12:33
C'est carrément un mini-programme dans Linux...

Pourquoi pas?

Merci
0
zipe31 Messages postés 36402 Date d'inscription dimanche 7 novembre 2010 Statut Contributeur Dernière intervention 27 janvier 2021 6 415
8 févr. 2011 à 12:41
while read line
do
grep -l 'kill' /usr/bin/${line} 2>/dev/null
done < <(ls -li /usr/bin | grep "2 root" | grep -Ev '/$' | sort -n | awk '{ print $9 }')


Ce qui donne chez moi (la 1ère commande c'est pour avoir la liste des fichiers présents et triés correspondant aux critères "ls -li /usr/bin | grep "2 root"") :

$ ls -li /usr/bin | grep "2 root" | grep -Ev '/$' | sort -n | awk '{ print $1,$9 }'            
133276 perlbug*
133276 perlthanks*
135128 skill*
135128 snice*
135129 pgrep*
135129 pkill*
141198 python*
141198 python2.6*
152795 sudo*
152795 sudoedit*

$ while read line; do grep -l 'kill' /usr/bin/${line} 2>/dev/null; done < <(ls -li /usr/bin | grep "2 root" | grep -Ev '/$' | sort -n | awk '{ print $9 }')
/usr/bin/skill
/usr/bin/snice
/usr/bin/pgrep
/usr/bin/pkill

$
0