Searching multiple patterns (words) with ack?
This should be enough:
ack -R 'string1|string2'
As -R
is the default, you can omit it:
ack 'string1|string2'
From man ack
:
-r, -R, --recurse
Recurse into sub-directories. This is the default and just here for
compatibility with grep. You can also use it for turning --no-recurse
off.
If you want to get the pattern from a file, say /path/to/patterns.file, you can use:
ack "$(cat /path/to/patterns.file)"
or equivallently:
ack "$(< /path/to/patterns.file)"
I cannot find an exact equivalent to grep -f
.
ack - search for multiple patterns (logical AND)
/foo/s && /bar/s && /baz/s
can be written as
/^(?=.*?foo)(?=.*?bar)(?=.*?baz)/s
We don't actually need a look ahead for the last one.
/^(?=.*?foo)(?=.*?bar).*?baz/s
And since we don't care which instance of the pattern is matched if there are more than one, we can simplify that to
/^(?=.*foo)(?=.*bar).*baz/s
How can I use ack to find files that contain two patterns?
I take it from your question that you want files that contains pattern1 and also contain pattern2, even if they are on different lines.
Here's one way to do it:
ack -l pattern2 $(ack -l pattern1)
Here's another:
ack -l pattern1 | ack -l -x pattern2
The -x
says "Get the list of files to search from standard input, as if I were the xargs
program." (This is assuming you're using ack 2.x or higher)
Multiple patterns with ack-grep?
ack
uses Perl regular expressions, and those allow lookahead assertions:
^(?!.*bar).*foo.*$
will match a line that contains foo
but doesn't contain bar
.
I'm not familiar with the usage of ack
, but something like this should work:
ack '^(?!.*bar).*foo.*$' myfile
grep/ack on Mac OS X finding multiple strings and respecting file types
Here's a script that combines the closely-named awk
and ack
commands:
find . -iname '*.r' | while read file; do
awk '
BEGIN { IGNORECASE=1; sawWordA = 0; sawWordB = 0 }
/wordA/ { sawWordA = 1 }
/wordB/ { sawWordB = 1 }
sawWordA && sawWordB { exit } # stop reading lines if both matches seen
END { exit !(sawWordA && sawWordB) }
' \
"${file}" \
&& ack --nofilter -H -i 'wordA|wordB' "${file}"
done
The awk command...
- Lists only the files where both strings appear irrespectively of the order
- Ignores the case
...and the ack command...
- Prints the lines where the strings appear
- Highlights the found words in colour
- Prints the file name as a header and lines under the header inspired by the ack options
- Ignores the case
The awk script sets flags if there are search string matches. If both strings have been matched, then the snippet exit !(sawWordA && sawWordB)
will return 0. If awk returns 0, then the ack command runs.
The ack --nofilter
option tells ack to avoid reading from STDIN. Otherwise, ack would try to use the STDIN that the read
command is using.
In the comments, Konrad asked how to use the above code when passing in variables in a shell script. Below is an example:
#!/bin/sh
if [ $# -ne 2 ]; then
echo Usage: $0 {string1} {string2}
E_BADARGS=65
exit $E_BADARGS
fi
find . -maxdepth 1 -iname '*.r' | while read file; do
awk "
BEGIN { IGNORECASE=1; sawArg1 = 0; sawArg2 = 0 }
/$1/ { sawArg1 = 1 }
/$2/ { sawArg2 = 1 }
sawArg1 && sawArg2 { exit } # stop reading lines if both matches seen
END { exit !(sawArg1 && sawArg2) }
" \
"${file}" \
&& ack --nofilter -H -i "$1|$2" "${file}"
done
The above example doesn't escape any special characters in the arguments provided to the script. If escaping is needed, the script can be modified as needed.
How do I search for the string '--branch' using ack?
Ack uses the Getopt::Long module to process command line arguments, so it supports the --
option to indicate that you want option processing to end at that point in the argument list.
ack -a -- --branch
should therefore work (it does for me).
How can I tell ack to search in two distinct directories?
Yes, you can specify any number of files or directories you want to search.
Look at the first line of ack --help
.
Usage: ack [OPTION]... PATTERN [FILES OR DIRECTORIES]
(The ack manpage has a similar usage statement)
So you can do
ack needle this_haystack/ that/haystack/ other/haystack*.txt
ack regex: Matching two words in order in the same line
You want to find word_1
, followed by anything, any number of times, followed by word_2
. That should be
word_1.*word_2
You seem to be using *
as it is often used in command line searches, but in regexes is it a quantifier for the preceding character, meaning match it at least 0 times. For example, the regex a*
would match 0 or more a
s, whereas the regex a+
would match at least one a
.
The regex metacharacter meaning "match anything" is .
, so .*
means "match anything, any number of times. See perlrequick for a brief introduction on the topic.
Related Topics
How to Boot the Linux Kernel Without Creating an Initrd Image
200,000 Images in Single Folder in Linux, Performance Issue or Not
Can't Build 32Bit Wine on 64Bit Linux
Unable to Start Rstudio in Centos Getting Error "Unable to Connect to Service"
Export Variables Defined in Another File
How to Do Versioning of Shared Library
Mpi_Send Takes Huge Part of Virtual Memory
How to Detect a Buffer Over Run on Serial Port in Linux Using C++
Determine Tsc Frequency on Linux
Match All Files Under All Nested Directories with Shell Globbing
How to Open a File in Assembler and Modify It
Git - Windows and Linux Line-Endings
Shell Script to Copy and Prepend Folder Name to Files from Multiple Subdirectories