Grep pour windows

0/5 (10 avis)

Snippet vu 7 903 fois - Téléchargée 16 fois

Contenu du snippet

Il s'agit d'un programme qui recherche et met en valeur des chaînes de caractères dans des fichiers ou dans un flux capturé en pipe.
J'avais besoin d'un équivalent du grep des UNIX que je ne trouvais pas sous windows.

Source / Exemple :


using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace Grep
{
	class Program
	{
		static RegexOptions regexOptions = 0;
		static bool displayLineNumber = false;
		static ConsoleColor lineNumberColor;
		static ConsoleColor highlightColor;
		static bool CountOccurences = false;
		static bool displayOccurences = true;
		static bool grepConsole = false;
		static SearchOption fileSearchOptions = SearchOption.TopDirectoryOnly;
		static Regex searches;
		static TextWriter output;
		
		/// <summary>
		/// Permet de parser les arguments de la ligne de commande
		/// </summary>
		static Regex argsParser = new Regex(@"^/(?<name>\w+)(:(?<value>\w+))?$", RegexOptions.Singleline | RegexOptions.ExplicitCapture);

		static void Main ( string[] args )
		{
			if (args.Length < 2) {
				help(null);
			}

			string wildcard = args[0];
			//si le chemin commence par /c
			if (wildcard.StartsWith("/c")) grepConsole = true;
			//extrait le nom du répertoire et le masque de la 
			string files = Path.GetFileName(wildcard);
			string path = wildcard.Substring(0, wildcard.Length - files.Length);
			if (path == string.Empty) path = ".";

			//les les options dans les paramètres
			ReadOptions(args);
			output = new StreamWriter(Console.OpenStandardOutput());
			if (output==null) output = Console.Out;

			if (grepConsole) {
				//dans le cas d'une lecture du pipe, ouvre le pipe
				using (TextReader s = new StreamReader(Console.OpenStandardInput())) {
					//puis le filtre
					ExtractDatasFromStream(s);
				}
			} else {
				//dans le cas d'une lecture fichiers
				//vérifie l'existence des fichiers
				if (!Directory.Exists(path)) {
					help("Le chemin spécifié n'existe pas");
				}

				//récupère la liste des fichiers à filtrer
				string[] filenames = Directory.GetFiles(path, files, fileSearchOptions);

				foreach (string filename in filenames) {
					//affiche le nom du fichier
					Console.WriteLine("-- {0} {1}", filename, new string('-', filename.Length < 74 ? 76 - filename.Length : 2));

					//ouvre le fichier
					using (TextReader s = new StreamReader(File.OpenRead(Path.Combine(path, filename)))) {
						//puis le filtre
						ExtractDatasFromStream(s);
					}
				}
			}
		}

		/// <summary>
		/// Extrait les données du flux en fonction des recherches indiquées
		/// </summary>
		/// <param name="s">flux à filter</param>
		private static void ExtractDatasFromStream ( TextReader s )
		{
			ConsoleColor defaultConsoleColor = Console.ForegroundColor;
			int i = 0;
			int occurences = 0;
			bool first = true;
			while (true) {
				i++;
				string line = s.ReadLine();
				if (line == null) break;
				MatchCollection matches = searches.Matches(line);
				if (matches.Count > 0) {
					//affiche le numéro de ligne
					if (displayLineNumber) {
						Console.ForegroundColor = lineNumberColor;
						if (!displayOccurences && !first) {
							output.Write(",");
						} else {
							first = false;
						}
						output.Write(i);
						if (displayOccurences) {
							output.Write(":");
						}

						output.Flush();
						Console.ForegroundColor = defaultConsoleColor;
					}
					int pos = 0;
					//affiche les lignes sur lesquelles la valeur a été trouvée
					if (displayOccurences) {
						foreach (Match match in matches) {
							//met en valeur la valeur
							output.Write(line.Substring(pos, match.Index - pos));
							output.Flush();
							Console.ForegroundColor = highlightColor;
							output.Write(line.Substring(match.Index, match.Length));
							output.Flush();
							//revient à la couleur par défaut
							Console.ForegroundColor = defaultConsoleColor;
							pos = match.Index + match.Length;
						}
						output.WriteLine(line.Substring(pos));
						output.Flush();
					}
					occurences += matches.Count;
				}
			}
			if (CountOccurences) {
				if (displayOccurences || displayLineNumber) output.WriteLine();
				output.WriteLine("{0} occurences", occurences);
				output.Flush();
			}
		}

		/// <summary>
		/// Lit les options dans les arguments
		/// </summary>
		/// <param name="args"></param>
		private static void ReadOptions ( string[] args )
		{
			lineNumberColor = Console.ForegroundColor;
			highlightColor = Console.ForegroundColor;

			List<string> stringSearches = new List<string>();
			bool inOptions = true;
			for (int i = 1; i < args.Length; i++) {
				if (inOptions) {
					Match m = argsParser.Match(args[i]);
					if (m.Success) {
						switch (m.Groups["name"].Value) {
							case "i": regexOptions |= RegexOptions.IgnoreCase;
								break;
							case "h":
								if (m.Groups["value"].Success) {
									highlightColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), m.Groups["value"].Value, true);
								} else {
									help("l'argument h doit avoir une valeur");
								}
								break;
							case "n": displayLineNumber = true;
								if (m.Groups["value"].Success) {
									lineNumberColor = (ConsoleColor)Enum.Parse(typeof (ConsoleColor), m.Groups["value"].Value, true);
								}
								break;
							case "d": fileSearchOptions = SearchOption.AllDirectories;
								break;
							case "o": CountOccurences = true;
								break;
							case "O": CountOccurences = true; displayOccurences = false;
								break;
						}
						continue;
					}
					inOptions = false;
				}
				stringSearches.Add(args[i]);
			}
			if (stringSearches.Count == 0)
				help("La ligne de commande doit contenir au moins une chaîne de recherche");
			searches = new Regex("(" + string.Join("|", stringSearches.ToArray()) + ")", regexOptions);
		}

		/// <summary>
		/// Affiche l'aide et cort du programme
		/// </summary>
		/// <param name="message">Message à afficher avant l'aide</param>
		private static void help (string message)
		{
			if (message != null) {
				Console.WriteLine(message);
				Console.WriteLine();
			}
			Console.WriteLine("GREP");
			Console.WriteLine("Filtre les fichiers en fonction de la chaîne de recherche spécifiée");
			Console.WriteLine();
			Console.WriteLine("Syntaxes :");
			Console.WriteLine("\t GREP [chemin\\]masque /i [/n[:couleur]] /h:couleur chaine1 [chaine2 [chaine3...]]");
			Console.WriteLine("\t pipe | GREP /c /d /i [/n[:couleur]] /h:couleur chaine1 [chaine2 [chaine3...]]");
			Console.WriteLine();
			Console.WriteLine("Arguments : ");
			Console.WriteLine("\t/c\tFiltre le pipe");
			Console.WriteLine("\t/s\tRecherche dans les sous répertoires");
			Console.WriteLine("\t/i\tPermet d'ignorer la casse");
			Console.WriteLine("\t/n\tAffiche les numéros de ligne");
			Console.WriteLine("\t/h\tChange la couleur de la valeur trouvée");
			Console.WriteLine("\t/o\tCompte le nombre d'occurences trouvées");
			Console.WriteLine("\t/O\tCompte le nombre d'occurences trouvées sans les afficher");

			Environment.Exit(0);
		}
	}
}

A voir également

Ajouter un commentaire

Commentaires

cs_Warny
Messages postés
478
Date d'inscription
mercredi 7 août 2002
Statut
Membre
Dernière intervention
10 juin 2015
-
J'ai analysé ton lien, et voilà donc l'équivalent de mon programme en powershell :
ls $wildcard |% { echo "----- $_.FullName ------------------------------"; get-content $_.FullName | select-string $searchstring }
nhervagault
Messages postés
6063
Date d'inscription
dimanche 13 avril 2003
Statut
Modérateur
Dernière intervention
15 juillet 2011
23 -
cs_Warny
Messages postés
478
Date d'inscription
mercredi 7 août 2002
Statut
Membre
Dernière intervention
10 juin 2015
-
J'ai essayé, en fait il recherche sur la sortie de la commande précédente qui est la liste de fichiers. Il doit donc y avoir besoin d'un intermédiaire pour récupérer le contenu.
nhervagault
Messages postés
6063
Date d'inscription
dimanche 13 avril 2003
Statut
Modérateur
Dernière intervention
15 juillet 2011
23 -
Il me semble que la derniere commande recherche dans le contenu des fichiers
(ce qui est fait par le select-string)

J'ai pas powershell sur cette machine et j'ai pas encore travailler avec cet outil.
cs_Warny
Messages postés
478
Date d'inscription
mercredi 7 août 2002
Statut
Membre
Dernière intervention
10 juin 2015
-
Re, en fait, la commande que je propose cherche dans le contenu des fichiers et pas seulement dans le nom comme tu le propose en powershell. Il n'empêche que tu donne une bonn piste pour implémenter la même fonctionnalité.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.