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

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.

Related

What does the "-Np1" option for the patch command do?

Someone sent me a patch and told me to apply it using the command:
patch -Np1 -i file.patch
Out of curiosity, I tried to find out what the -Np1 option does but the patch man page is curiously opaque on this. Can anyone explain what this does? Thanks.
It's two flags. -N and -p1.
-N or --forward
Ignore patches that seem to be reversed or already applied. See
also -R.
and
-pnum or --strip=num
Strip the smallest prefix containing num leading slashes from each
file name found in the patch file. A sequence of one or more adja-
cent slashes is counted as a single slash. This controls how file
names found in the patch file are treated, in case you keep your
files in a different directory than the person who sent out the
patch. For example, supposing the file name in the patch file was
/u/howard/src/blurfl/blurfl.c
setting -p0 gives the entire file name unmodified, -p1 gives
u/howard/src/blurfl/blurfl.c
without the leading slash, -p4 gives
blurfl/blurfl.c
and not specifying -p at all just gives you blurfl.c. Whatever you
end up with is looked for either in the current directory, or the
directory specified by the -d option.

The best way in Unix to add a header to multiple files in a directory?

Before anyone else checks, I am confident this is not a duplicate of the existing question of how to add a header in Unix to multiple files (the question is here: Adding header into multiple text files). This is more about optimisation of a solution I am currently using for this current issue.
I have numerous directories in which I have over 20000 files and for each file I want to add the same header.
What I have been doing is:
sed -i '1ichr\tpos\tref\talt\treffrq\tinfo\trs\tpval\teffalt\tgene' *.txt
Now, this does work exactly as I want it to, but there have been a couple of issues.
First is that this seems to be an extremely slow method of doing this and it can take a pretty long time to get through all 20K+ files.
Second, and more frustratingly, occasionally my connection to the server I am using has timed out during this long process meaning that the command won't finish running, so I end up with half the files having the header and half not. And if I started from the top again this would mean a number of the files would have the header twice so I actually have to go through a process of creating them again so I can add the header all at once.
So, what I am wondering is if there is a better/quicker solution to this problem. The question I linked above seems like it would actually be slower (given that it seems like there is more the command line needs to do at each file as it is going through a loop) and so doesn't seem like it would fix this.
Don't use -i. It confuses things when you get interrupted. Instead, use
mkdir -p ../output-dir
for file in *.txt; do
sed '1ichr\tpos\tref\talt\treffrq\tinfo\trs\tpval\teffalt\tgene' "$file" > ../output-dir/"$file"
done
When you're done, you can rename the directories if you wish. This doesn't address the connection issue (ThoriumBR's suggestion of nohup is good for that), but when it happens you can recover state more easily.
First, adding a header is slow. You have to move the entire file contents to add something at the start. Adding a trailer would be very fast.
Second, use nohup:
nohup - run a command immune to hangups, with output to a non-tty
Using nohup sed -i '1ichr\tpos\tref\talt\treffrq\tinfo\trs\tpval\teffalt\tgene' *.txt will keep the command running on the background even if the server times you out.

Dumbed down patch command

I would like to issue a patch command which is somewhat dumber than the default, but I cannot find the right flags (if they exist at all).
I don't want it to create .rej or .orig files, not even when the patch fails. If the patch fails I'd like the original files to remain unchanged.
I don't want it to try guessing if the patch is reversed or not, or try matching the lines before or after those given in the patch. If the lines at the given line numbers do not match, it should fail.
I've tried with -f -N -V never -r - --no-backup-if-mismatch, but still backup files are created and "fuzzy" matching is tried.
Run it with --dry-run -s and only apply if it doesn't report any problems (you may be able to key off the return code).
For disabling the fuzz, you need -F0

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