Skip to content

Instantly share code, notes, and snippets.

@preetpalS
Last active August 20, 2023 11:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save preetpalS/2fd6c6bf05a94734f89b70b679716bf3 to your computer and use it in GitHub Desktop.
Save preetpalS/2fd6c6bf05a94734f89b70b679716bf3 to your computer and use it in GitHub Desktop.
Command line utility to find files using globs or regex (written in D)
import std.file, std.stdio;
immutable string programInformation = "Searches for files based on their names.\n"
~ "Search case sensitivity depends on the OS (macOS and Windows are case-insensitive while non-macOS POSIX systems are case-sensitive).\n\n"
~ "OPTIONS:";
immutable string versionInformation = "Filename Searcher (find_file) 1.0.1\n"
~ "Copyright (C) 2022 Preetpal Sohal.\n"
~ "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
~ "This is free software: you are free to change and redistribute it.\n"
~ "There is NO WARRANTY, to the extent permitted by law.\n\n"
~ "Written by Preetpal Sohal.";
auto findFilesUsingRegex(string directory, string regex_string, bool followSymlinks)
{
import std.algorithm, std.path, std.regex;
auto re = regex(regex_string, std.path.CaseSensitive.osDefault ? "" : "i");
return dirEntries(directory, SpanMode.depth, followSymlinks).filter!(f => matchFirst(f.name, re));
}
auto findFilesUsingWildcard(string directory, string wildcard, bool followSymlinks)
{
return dirEntries(directory, wildcard, SpanMode.depth, followSymlinks);
}
void printMatches(T)(T matches)
{
foreach (de; matches)
{
writeln(de.name);
}
}
int main(string[] args)
{
import std.getopt;
try
{
bool regex = false;
bool displayVersion = false;
bool followSymlinks = false;
auto programOptions =
getopt(args,
"regex", "treat search string as a regex instead of a wildcard.", &regex,
"version", "display version information and exit", &displayVersion,
"follow-symlinks", "follow symlinks during directory traversal", &followSymlinks);
if (programOptions.helpWanted)
{
writefln("Usage: %s [option]... search [directory]\n", args[0]);
defaultGetoptPrinter(programInformation, programOptions.options);
return 0;
}
if (displayVersion)
{
writeln(versionInformation);
return 0;
}
if (args.length < 2)
{
writefln("Usage: %s [option]... search [directory]", args[0]);
defaultGetoptPrinter(programInformation, programOptions.options);
return 1;
}
string search = args[1];
string directory = ".";
if (args.length > 2)
directory = args[2];
if (!regex)
{
printMatches(findFilesUsingWildcard(directory, search, followSymlinks));
}
else
{
string regex_string = args[1];
printMatches(findFilesUsingRegex(directory, search, followSymlinks));
}
}
catch (Exception e)
{
writeln(e.msg);
return 1;
}
return 0;
}
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</asmv3:windowsSettings>
<asmv3:windowsSettings xmlns:ws3="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
<ws3:activeCodePage>UTF-8</ws3:activeCodePage>
</asmv3:windowsSettings>
</asmv3:application>
<assemblyIdentity type="win32" name="PreetpalSohal.find_file" version="1.0.0.8"></assemblyIdentity>
</assembly>
@preetpalS
Copy link
Author

The manifest file is needed on Windows for long paths (like in a node_modules directory). In Windows, the executable must be named as find_file.exe and the manifest file must be placed in the same directory as the find_file.exe executable for the long path awareness to work. Also note that it is possible to embed the manifest file in the executable. Compile using LDC2 D compiler with command ldc2 -O3 -release -mcpu=native -m64 find_file.d -o find_file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment