This project has been officially archived and is no longer being maintained or updated. This decision was made because other tools more or less already solve the same problem.
I recommend the following projects for users seeking alternatives:
- ripgrep - Designed for speed, filtering by default, fewer bugs and Unicode support.
- ugrep - True drop-in replacement for GNU grep, equipped with a ton of new features that users wanted.
A simple search tool supporting multiple file patterns and keywords, and the ability to also do replaces.
Recursively searches for files in the current directory matching the given file patterns, and having content matching the given regular expressions. The output is colored for better readability.
The tool can also read from STDIN, which is the case if no file pattern is given.
For each search pattern you can also optionally specify a replace text.
Configuration files are supported for user-specific and project-specific file path exceptions.
I have considered Ack, but I prefer more readable outputs, sometimes I want to
search for multiple patterns, Ack cannot replace text in files, and I don't care about vi
.
-
Ack was written in Perl, and requires no extra modules to install. Mine was first written in Perl too, but had to rewrite it in Groovy because it did use extra modules, and CPAN started becoming unusable. While the Groovy code can use any Java library we want. Also, Perl can be very complex and hard to read, and maintain.
Groovy definitely can't beat the speed of Perl. This is an example, where
sP
was the Perl implementation of my tool, andsG
was the Groovy one:$ time sP -a - Test (...) real 0m7.179s $ time sG -a - Test (...) real 0m11.902s
Although in the past I made optimizations to increase performance, I do not think this speed we have now is significantly bad anymore.
-
Ack limits me too much. It supports only directory names to ignore, while I support path patterns specified as regexes. I can't specify file name patterns in Ack while my tool supports glob patterns.
While Ack ignores certain directories by default, e.g.
build
,.git
, and my tool doesn't, I can still configure the same too. -
Output is not user friendly to me.
Example:
$ ack --ignore-dir=build -C 3 Test src/test/groovy/search/util/GlobPatternTest.groovy package search.util import org.junit.Test class GlobPatternTest { @Test void globPatternWorks() { assert new GlobPattern('*.java').matches(Paths.get('Test.java')) } }
$ build/dist/search \*GlobPatternTest\* - Test ./src/test/groovy/search/util/GlobPatternTest.groovy : (...) package search.util 9 : import org.junit.Test 11 : class GlobPatternTest { 13 : @Test void globPatternWorks() { 15 : assert new GlobPattern('*.java').matches(Paths.get('Test.java')) }
It must be a bug that line numbers disappear when I specify an exact file path in Ack, because normally it looks like this:
src/test/groovy/search/util/GlobPatternTest.groovy 6- 7-package search.util 8- 9:import org.junit.Test 10- 11:class GlobPatternTest { 12- 13: @Test 14- void globPatternWorks() { 15: assert new GlobPattern('*.java').matches(Paths.get('Test.java')) 16- } 17-}
Even with colors I find it ugly.
- The tool was written primarily for use on Linux & Mac, but git bash for Windows is also supported. The implemented binary file detection does not work natively on Windows, as text encoding on there is quite different.
- Java Runtime Environment version 17 or newer
Unzip/untar the release package to a directory you prefer, e.g. ~/programs/
, and rename
~/programs/search-<VERSION>
to ~/programs/search
.
Then the executable to run is ~/programs/search/bin/search
, however, please see
chapter Usage about how to make the tool easier to use.
Assuming you have gng installed, execute the following steps:
cd ~/projects
git clone $URL
cd search
gw assemble
Then either you can unpack the distribution package in build/distributions
as described in the previous section, or you can
run gw installDist
and use build/install/search
as the extracted location.
Optionally, to ensure you got a working revision:
gw test integrationTest
-
Create a configuration file at
~/.search.conf
, then put generic file path exclude patterns there. See configuration example below. -
Optionally, create a configuration file for each project, eg. under
./.local
, and put your project-specific exclude patterns in there. (Exclude everything that makes your results shown practically twice. Usually you want to exclude build directories.)You can also include the default configuration created in the previous step, with variable
includeConfig
. -
To support automatic use of the project-specific configuration, create the following bash function, and put it into your private
~/.bashrc
:search() { local args='' if [ -f '.local/search.conf' ]; then args='-c .local/search.conf' fi ~/programs/search/bin/search $args "$@" } # Also add a much shorter alias because we hate typing. alias s=search
For a list of command line arguments see:
s --help
Uses Groovy syntax, see ConfigSlurper.
-
contextLines: int
Number of context lines to display (before and after matched lines). -
excludePatterns: List<String>
List of regular expressions to exclude directory paths and file paths. You can of course use slashy strings and dollar-slashy strings, so you don't have to escape characters. -
includeConfig: List<String>
Allows extension of the current config file with other ones. (Warning: avoid circular includes!) Supports both absolute paths and paths relative to the current config file. The included config will always override options of its parent config, regardless of where you put this option. -
printHtml: boolean
Print the results in HTML and open in a browser. -
tmpDir: String
Location of the temporary directory used for replacements and HTML output. The default value is taken from Java system propertyjava.io.tmpdir
.
The following is an actual config I use as a user-specific config (~/.search.conf
):
maxContextLines = 3
excludeFilePatterns = [
$//\.git//$,
$//build//$,
$//dist//$,
$//target(.+?)//$,
$//node_modules//$,
$//\.gradle//$,
$//\.idea//$,
$//out//$,
$//bin//$,
/\.bak$/,
$/\.\#(.+?)(\.\d+)+/$
]
In this example we automatically skip searching in text files that are generated/built (a fine-tuning of this may desired for your project), ones that are SVN metafiles, and ones that are temporary files created by Eclipse to show history.)
-
Basic searches:
s \*.js - jQuery s \*.java - 'System\.out\.println' s \*.java \*.js - myCode 'myThing(s)?' s \*.java - MyCode '(my|their)code'
-
Case insensitive search:
s -i \* - regex processor
-
Hide the keyword
processor
in results:s \* - regex -h processor
-
Search for the character sequence
-h
:s \* - '\-h'
-
Search from the output of command
git blame
:git blame someFile | search - someAuthor
-
Search in every file (including hidden ones):
s -a - myproject
-
Execute a command for every file found (which can be much faster than regular
findf
):s -C .project | xargs git add
-
Search for
jQuery
and replace each occurrence with$
:s \* - 'jQuery' -r '$'
-
Search for
jQuery
and replace each occurrence with$
, but only in files including a script tag:s \* - 'jQuery' -r '$' '<script'
-
Import project in IntelliJ IDEA (e.g. the Community Edition).
-
Make sure Project Code Style is used as set in
.editorconfig
(This is needed to keep formatting compatible with CodeNarc.) -
Before committing:
gw clean build
-
How to commit: Please send a PR. :)
I will carefully review it during my free time. (This is not a paid project.)
-
Read some docs: