Ack is a very flexible utility which can be used to perform searches inside source code, plenty of programmers are tempted of using grep for doing this, but as we will see, ack provides a much more flexible alternative to the classical grep in coding scenarios. This tutorial collects typical usage scenarios of ack, notice that ack is developed in Perl, and a faster although not so flexible version written in C is 'ag', if something faster is needed, just check it out.
ack 'pattern'
# searches for that pattern in all files starting from current directory and all
# its subdirectories except .svn and .git
ack 'pattern' path/to/dir
# searches for that pattern in all files starting from specified directory and all
# its subdirectories except .svn and .git by default
ack 'pattern' -w
# uses word boundaries, in order to not match pattern within another string
ack 'pattern' --ignore-dir env/ --ignore-dir dataset/
# searches for pattern but ignores everything inside the specified directories
ack 'pattern' --ignore-file=ext:pod,t,py,csv,tsc
# searches for pattern but ignores all the files who have the specified
# extensions
ack 'pattern' --ignore-file=match:/^#.+#$/
# searches for pattern but ignores all the files who match the specified regular
# expression
ack 'pattern' -l
# only prints the file names containing the pattern
ack 'pattern' -L
# only prints the file names NOT containing the pattern
ack 'pattern' -g
# only prints file names matching either base name or absolute path
# with pattern
ack -g log --ruby
# prints all the files which have in their path/name the specified pattern
# and or of type ruby
ack -g log --noruby
# prints all the file which have in their path/name the specified pattern
# but do not belong to the ruby type, remember that an ack --dump
# also helps us inspecting various types
ack pattern -n
# only searches in current directory without going into subdirectories
ack file1 --match foo
# the --match option allows us to defer the specification of the match
# so that it is not the first given parameter
ack pattern --pager=less
# allows the view of the results through a pager without suppressing colors and
# syntax highlighting
ack pattern -i
# search for pattern ignoring case
ack -Q pattern
# search for pattern doing a literal search, like fgrep, so we do not take into
# account regexes
ack -Q aa.bb.cc.dd /path/to/access.log
# search for pattern doing a literal search, like fgrep, so we do not take into
# account regexes metacharacters
ack --help=types
# shows help in order to do search with respect to file types,
Now if from type we see that in order to search for .sh and .ksh files
we have to specify --bash
or --nobash
we can include that in our searches for
example:
ack pattern --nobash
let's see a more complicated example:
ack pattern --nopython --ignore-dir env/ --pager=less
ack -f --python
# prints all the filenames of type 'python'
# this can be useful for debugging purposes especially
# when we define our own types
ack pattern -v
# works like in grep, will make the negation of the pattern and search for lines
# not containing that pattern
ack --match 'clone.*deep|deep.*clone' --nopython --ignore-dir env/ --pager=less
# searches all the files which are not python and not in the env/ directory and
# who have on the same line either the sequence clone <sommething> deep or
# deep <something> clone
ack -l pattern2 $(ack -l pattern1)
# files that contains pattern1 and also contain pattern2, even if they are on
# different lines.
ack pattern -C 4
# gives 4 lines of context around matching lines
ack pattern -B 4
# gives 4 lines of context around matching lines
# taking lines before the matching line
ack pattern -A 4
# gives 4 lines of context around matching lines
# taking lines after the matching line
ack pattern -c
# prints out for each file the number of matches for the specified pattern
# if also -l is active it will only show the number of matchine lines for
# files which are matching
ack pattern -ch
# prints out for each file the number of matches for the specified pattern
# with the -h option active, we suppress the filenames and only get a total
# sum of matches
ack pattern -ch -w --python
# print the number of matches for the word `pattern` in all python files
ack pattern --files-from=filelist.txt
# searches the pattern only in the files specified in the mentioned file
ack --dump
# prints all the current configuration with which ack is running,
# this is very useful for debugging purposes but also to understand
# how certain options have to be set or how a type of file is defined
We can specify output options for our searches, for example, let's say we want to wrap all the words containing the letter 'e' around underscores, we can do something like:
ack2.pl "\w*e\w*" quick.txt --output="$`_$&_$'"
with the --output
option we have special expansion strings which are:
$&
The whole string matched by PATTERN.$1, $2, ...
The contents of the 1st, 2nd ... bracketed groups in PATTERN- `$`` The string before the match
$'
The string after the match
We generally can substitute grep with ack in many cases, let's see some examples:
ack 'type \w+' README.md -oh
# outputs only the text matching the specified pattern, this is very
# useful especially when we want to extract text or remove text from a file
# or more files
ack 'classifier \w+' ML_NOTES -c
# counts the occurrences of the specified pattern
ack 'classifier \w+' ML_NOTES -i
# performs a case-insensitive search of the pattern
Notice that the position of the flags is not important, we can also put those just after 'ack'.
ack pattern --type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx --cpp
# here we are defining a file type called cpp with the supported extensions
# being cpp,cc,cxx,hpp,hh,h,hxx
# this is just used as a demo example, since this type already exists by default
# in ack then we search for these files using the mentioned pattern
We can also define types by inspecting the first line of the file, this is
useful for example for types of files who use shebang notation #!
and so on,
let's see an example:
ack pattern --type-add=sctv:firstlinematch:/^sctv/ --sctv
# here we are defining a file type called sctv which is characterized by files
# having as a first line starting with the string sctv
# then we search for these files using the mentioned pattern
By default Ack tries to read ~/.ackrc
and .ackrc
in the current directory
as the default configuration files, if these do not exist it still has a
default configuration. We can change Ack configuration by first printing
its current default configuration on the standard output and saving it
to a file.
We can do this by issuing:
ack --create-ackrc > .ackrc
# saves to a file current ackrc configuration
and then by editing the .ackrc
as we wish.
So for example by defining our own types or telling ack which directories
to ignore and so on.
We can manually specify a configuration file to ack by using:
ack pattern --ackrc .myconf.ackrc
# loads the mentioned configuration file as last, so it will have a
# higher priority
If we changed our Ack configuration file .ackrc
we can test the changes by
executing a ack --dump
and checking if our change is listed in the current
configuration.
We can take advantage of ack capabilities to also replace strings with the help of other programs, e.g., perl or sed.
perl -p -i -e's/this/that/g' $(ack -f --perl)
or with gnu sed:
sed -i 's/oldstring/newstr/gI' $(ack -f --perl)
notice that the BSD version of sed may not support the option I
for
case-insensitivity.