Ack — Ignoring multiple directories without repeating the flag - ack

Is it possible to ignore multiple directories in Ack, without repeating the flag?
e.g. I know the following works (i.e. setting multiple flags):
ack --ignore-dir=install --ignore-dir=php 'teststring'
I was hoping that I could separate directories with commas, like I can do with the extensions as follows:
ack --ignore-file=ext:css,scss,orig 'teststring'
However, the following comma separated ignore flag doesn't work:
ack --ignore-dir=install,php 'textstring'
Is it possible to use some short-hand equivalent, so I don't have to repeatedly type out the --ignore-dir flag?

It's actually similar to how you would specify the include patterns for grep:
ack <term> --ignore-dir={dir_a,dir_b}
However, This format does not work with a single directory. So
ack <term> --ignore-dir={log}
will not work.

Since you're using ack 2, you can put --ignore-dir=install and --ignore-dir=php in a .ackrc file in the root of your project. Then, every ack invocation in that tree will use those flags.

So to ignore single directory use
ack <term> --ignore-dir=dir_a
and to ignore multiple directories use
ack <term> --ignore-dir={dir_a,dir_b}

One approach could be to select those directories to exclude with a regular expression in -G option complemented with the option --invert-file-match. Based in your question, something like the following:
ack -a -G 'install|php' --invert-file-match 'textstring' .

Related

Ack dooesn't show the line number when i search in the single file

example) When I search the exec in proc.c file,
$ ack allocproc proc.c
allocproc(void)
p = allocproc();
if((np = allocproc()) == 0){
// Return to "caller", actually trapret (see allocproc).
but when I search in the whole directory,
$ ack allocproc
---- blah blah blah ----
proc.c
36:allocproc(void)
84: p = allocproc();
139: if((np = allocproc()) == 0){
357: // Return to "caller", actually trapret (see allocproc).
... I want to show lines when I search a string in the single file...
Maybe add a line in .bashrc alias ackl='ack -H'
and use ackl command as default... will solve this temporarily.
The -H flag in ack will force ack to put a file header and line number on every file. This behavior is copied directly from GNU grep.
You point out the option of creating a shell alias. Another option is to put the -H in an ackrc file. ack supports three different places to find an ackrc. There's a system-wide one in /etc/ackrc, there's one that's personal to you in your ~/.ackrc file, and you can also have a project-specific file, typically in the root of a project.
For more about ackrc files, look at the ack manual (ack --man is one way to see it) and look for the section "THE .ackrc FILE" and "ACKRC LOCATION SEMANTICS".
The one downside to putting -H in your .ackrc is that it will always be in force no matter how you call ack, so if, for example, you're piping output from one process through ack, ack will still show the heading and line numbers.
One other way to deal with this: Just add the -H option when you need it.
I've discovered that, in both grep and ack, if they behave differently with one file than they do with multiple files, you can force the multiple-file behavior by including /dev/null as a second file to search through.
Of course, using the -H switch is much cleaner (and has the advantage of being listed in the documentation, so that curious maintainers can see the exact purpose behind its use), but if you're in a pinch and don't have the documentation available (or if you're using some other program that behaves differently with one vs. with multiple files), then using /dev/null will probably work.
I don't recommend using this /dev/null technique in commands called in scripts -- in such cases, the -H switch is the preferred method, unless for some reason -H is literally unavailable to you.

unix command line ...how to grep and show only file names that contain a string?

I know I can search for a string with:
grep -n -d recurse 'snoopy' *
and then it shows every file name and instance that contains that string, like:
file/name.txt:23 some snoopy here
file/name2.txt:59 another snoopy there
file/name2.txt:343 some more snoopy
etc...
The problem is that with many occurrences, the list is huge. How do I make it show only the actual file names that contain the string, without duplicates and without the occurrence?
Only like:
file/name1.txt
file/name52.txt
file/name28293.txt
Thanks a lot for any help :)
The -l flag (or, in both BSD and GNU grep, --files-with-matches) does what you want.
From the POSIX spec:
Write only the names of files containing selected lines to standard output. Pathnames shall be written once per file searched. If the standard input is searched, a pathname of "(standard input)" shall be written, in the POSIX locale. In other locales, "standard input" may be replaced by something more appropriate in those locales.
Both BSD and GNU also explicitly guarantee that this will be more efficient. (Older BSD versions say "… grep will only search a file until a match has been found, making searches potentially less expensive", newer BSD and GNU say "The scanning will stop on the first match".) If you don't know which grep you have and which options it has, just type man grep at the shell and you should get the manpage.

How can I implement the command 'ls' with wildcard, '*'?

EDIT #1 : I'm under the limit that all arguments are enclosed in two quotes, so that shell do not expand any argument with * to the corresponding path.
EDIT #2 : In order to retrieve directories such as */*, ../*, and dirA/*/file.out, How should I use iteration loop or recursive call?
I have just learned about the function fnmatch(). But I don't know start place.
There are many possible cases. I'm confused dealing with these all cases.
For example, Let me assume that executable program is a.out.
$./a.out -l */*
$./a.out -l ../*
$./a.out -l [file_name] [directory_name]
/* Since I also have to implement ls command with no wildcard. */
What should I do? Any advice would be awesome.
Thank you in advance.
Your problem is : shell replaces wildcard caracter * with all of the filenames matching the pattern.
Solution:
If you do not want to use this feature of bash, just put quotation marks around your command line arguments.
Calling your program that way will have the original arguments, containing wildcards.
After this, you can list all the filenames with their paths. For example using some recursive algorithm. Then you can apply some matching to these path string. (when visiting it)
If you want to be a good unix citizen, the rule is Don't do filename globbing unless you are writing a shell.
You want to write an ls-like program? Don't do any wildcard expansion. Don't treat "*" specially. Just treat your argv as a list of filenames. If your program handles these cases:
./a.out file1
./a.out file1 file2 file3
Then it will also handle
./a.out file*
correctly because the shell will do the expansion and your program won't need to know about it. And besides that, it will handle this:
zsh% ./a.out **/file<40-185>~file<90-100>(.mm-30OL[1,2])
which in zsh expanded glob syntax means: expand file40 through file185, except for file90 through file100, include only the ones that have been modified in the last 30 minutes, and use only the largest 2 files in the resulting set.
fnmatch is never going to do anything like that. But these fancy globs can be used with any command that just takes a filename list and doesn't care where it came from.
When you're in a situation where you can't take a list of filenames from the command line, then consider using fnmatch. ls isn't one of those situations.

Ack: Search directory tree for files with a particular extension

I basically just want to do ack foo *.citrus and have ack drill down and find the string 'foo' in all Citrus files in the current directory and below. The trouble is that this won't work if there aren't any Citrus files in the current directory.
I tried messing with -G without success. Do I really need to add a file type in .ackrc just to limit the search to files with a given extension?
As suggested by Andy Lester, you can also create a typeset without taking the trouble to add it in your .ackrc file:
ack --type-set=cit=.citrus --cit "foo"
By default, ack searches only in files with known types ( like *.java, *.cpp etc. ). It doesn't know about files *.citrus, so to search in such files you must use -a cmd line switch:
$ack -a -G '\.citrus$' foo
1.d/1.citrus
1:foo_bar
You don't have to set it in .ackrc if you don't want. You can also set ACK_OPTIONS in your environment, or specify --type-set arguments on the command line. ack doesn't care.

Can I create an ack file type based on a filename, not extension?

I would like to include files with a specific name -- not an extension -- in my ack search. Is this possible with ack?
If I use the -G option, this would exclude all other file types. (So I can't put it in my .ackrc file.)
I tried to use --type-set mytype=filename.txt but this only works for extensions, so this would search for files including the pattern .filename.txt, thus not find filename.txt. (That's also what the ack --help types shows: --mytype .filename.txt, not --mytype filename.txt.)
Someone any ideas?
man ack says that the files to be searched in can be given through standard input.
So this should work:
find . -name filename.txt | ack PATTERN -
Unfortunately, it doesn't. It gives ack: Ignoring 1 argument on the command-line while acting as a filter., which apparently is a bug in ack. When this bug will be fixed, we should be able to use
find . -name filename.txt | ack --nofilter PATTERN -
You also do it like if you're using zsh:
ack 'Pattern' **/filename.txt
What you're asking is "can I make a filetype that ack recognizes based on a filename", and the answer is "No, not in ack 1.x, but you can in ack 2.0". ack 2.0 is in alpha release, and we hope to have a beta by Christmas.
As #Christian pointed out above, you can specify the given filename on the command line, but that bypasses filetype checking entirely.
I know this is a late reply, but could you simply specify the filename when you run ack?
ack 'My Text' filename.txt

Resources