I would like to be able to easily repeat a find-grep. Ideally, it would work on recompile, which is what the g char runs. But at least when I run find-grep, it should start with the string that I last used in the same session, as a default. I have searched, but not found... Kind of ironic to be searching for an answer about searching...
Doesn't g do what you request already? For me it does.
But I'm talking about find-grep-dired, which might be useful for what you want to do.
I use find-dired+.el, in addition to vanilla find-dired.el. But I think that the latter probably does the right thing too.
Here's the doc string of find-grep-dired from find-dired+.el:
find-grep-dired is an interactive Lisp function in `find-dired+.el'.
(find-grep-dired DIR REGEXP &optional DEPTH-LIMITS EXCLUDED-PATHS)
Find files in DIR containing a regexp REGEXP.
The output is in a Dired buffer.
The `find' command run (after changing into DIR) is essentially this,
where LS-SWITCHES is `(car find-ls-option)':
find . -exec grep find-grep-options REGEXP {} \; LS-SWITCHES
Thus REGEXP can also contain additional grep options.
Optional arg DEPTH-LIMITS is a list (MIN-DEPTH MAX-DEPTH) of the
minimum and maximum depths. If nil, search directory tree under DIR.
Optional arg EXCLUDED-PATHS is a list of strings that match paths to
exclude from the search. If nil, search all directories.
When both optional args are non-nil, the `find' command run is this:
find . -mindepth MIN-DEPTH -maxdepth MAX-DEPTH
\( -path *edir1* -o -path *edir2* ... \)
-prune -o -exec grep find-grep-options REGEXP {} \;
LS-SWITCHES
Related
I want to grep in multiple sub directories, eg.
find subdir1 subdir2 -type f ( -name *.cc -o -name *.h ) -exec grep -e someString {} +
using emacs interactive rgrep. Is this possible? The rgrep in grep.el says:
but when I get to the "Base directory:" input, I can't figure out how to input more than 1 directory.
Is it possible to input more than 1 directory?
Thank you.
You can pass prefix arguments to rgrep to modify the command.
C-uM-x rgrep will take you through the normal prompts and then let you edit the result, at which point you can simply add the additional directories you wish to search to the initial find command.
C-uC-uM-x rgrep just gives you a bare template to edit immediately.
If all of the files are in sub-directories of a project, you might consider using the emacs projectile module. It handles multi-directory searching quickly and painlessly within a project.
I have a large file folder structure with many levels (without a pattern in naming convention). How do I run the following command to extract the data from all the folders? the command is:
perl -wne'while(/[\w\.\-]+#[\w\.\-]+\w+/g){print "$&\n"}'inputfile.txt > outputfile.txt
It works for one input file, but want it to go through all the text files in folders and subfolders.
I'd use find to call Perl with the "-i" option for in-place editing. With the "-i" option, you can optionally specify an extension for the saved unmodified file; without it, it modifies the file in-place without saving the unmodified file.
find dirs -name \*.txt -exec perl -i.orig -wne 'while(/[\w\.\-]+#[\w\.\-]+\w+/g){print "$&\n"}' {} \;
or (to start up Perl less often) use:
find dirs -name \*.txt -print | xargs perl -i.orig -wne 'while(/[\w\.\-]+#[\w\.\-]+\w+/g){print "$&\n"}'
Alternatively, you can use the File::Find module to walk the directory tree and then do your own in-place editing, but I think the above method is easier if you are on UNIX/Linux. (If on Windows, you might have to go this way.)
I have a directory tree which, among other files, has files which match certain patterns. For the sake of the discussion, let's assume these are files matching *.foo, or *.bar, or baz*. I want to backup inside my zsh-script only files matching these pattern to a new directory.
The seemingly obvious solution,
find fromdir \( -name '*.{foo,bar}' -o -name 'baz*' \) -exec cp {} todir \;
does not work, because the destination directory for, i.e., fromdir/x/y/a.foo does not exist.
I was thinking of using rsync, but I know only how to exclude certain files from being copied, not how to restrict copying.
I can solve the problem by writing a small auxiliary script, mdcp1file, like this:
#!/bin/zsh
set -u
mkdir -p $2/$1:h # Create destination directory if needed
cp $1 $2
and use it in my find command instead of cp. I wonder whether there is an easier way to solve this problem, either by beefing up the -exec of my find, or by using rsync in a clever way.
As you mention that you make use of zsh, you could just do something like this:
cd /path/to/source/dir
cp --parents **/{*.{foo,bar},baz*}(.) /path/to/destination/dir
Here we make use of:
cp --parents: Bash: Copy named files recursively, preserving folder structure
**: for matching over multiple directories
BRACE EXPANSION: A string of the form foo{xx,yy,zz}bar is expanded to the individual words fooxxbar, fooyybar and foozzbar. Left-to-right order is preserved. This construct may be nested. Commas may be quoted in order to include them literally in a word.
Glob Qualifier (.): Patterns used for filename generation may end in a list of qualifiers enclosed in parentheses. The qualifiers specify which filenames that otherwise match the given pattern will be inserted in the
argument list. The . selects files only.
I'd like to add a couple lines of text (copyright) to the top of all text files in a directory. Can I do this in emacs without copy/pasting for each file?
This is copied from Chris Conway's answer to a different question: Using Emacs to recursively find and replace in text files not already open
M-x find-name-dired: you will be prompted for a root directory and a filename pattern.
Press t to "toggle mark" for all files found.
Press Q for "Query-Replace in Files...": you will be prompted for query/substitution regexps.
Proceed as with query-replace-regexp: SPACE to replace and move to next match, n to skip a match, etc.
You can use it the same way
Yes, with
find . -type f -exec emacs -batch '{}' --eval '(insert-string "foo\nbar\nbaz\n")' -f save-buffer \;
or something to that effect. The emacs bit is
emacs -batch filename --eval '(insert-string "foo\nbar\nbaz\n")' -f save-buffer
replace "foo\nbar\nbaz" with your message. However, using emacs for this is really a lot of overkill. You could just put your copyright header into a file and use cat header file > tempfile; mv tempfile file.
How do I find and replace every occurrence of:
foo
with
bar
in every text file under the /my/test/dir/ directory tree (recursive find/replace).
BUT I want to be able to do it safely within an SVN checkout and not touch anything inside the .svn directories
Similar to this but now with the SVN restriction: Awk/Sed: How to do a recursive find/replace of a string?
There are several possiblities:
Using find:
Using find to create a list of all files, and then piping them to sed or the equivalent, as suggested in the answer you reference, is fairly straightforward, and only requires scanning through the files once.
You'd use one of the same answers as from the question you referenced, but adding -path '*/.svn' -prune -o after the find . in order to prune out the SVN directories. See this question for a discussion of using the prune option with find -- although note that they've got the pattern wrong. Thus, to print out all the files, you would use:
find . -path '*/.svn' -prune -o -type f -print
Then, you can pipe that into an xargs call or whatever to do the individual replacements, as suggested in the question you referenced. There is a lot of discussion there about different options, which I won't reproduce here, although I prefer the version from John Zwinck's answer:
find . -path '*/.svn' -prune -o -type f -exec sed -i 's/foo/bar/g' {} +
Using recursive grep:
If you have a system with GNU grep, you can use that to find the list of files as well. This is probably less efficient than find, but it does allow you to only call sed on the files that match, and I personally find the syntax a lot easier to remember (or figure out from manpages):
sed -i 's/foo/bar/g' `grep -l -R --exclude-dir='*/.svn' 'foo' .`
The -l option causes grep to only output the list of file names, rather than the matching lines.
Using a GUI editor:
Alternately, if you're using windows, do what I do -- get a copy of the NoteTab editor (available in a free version), and use its search-and-replace-on-disk command, which ignores hidden .svn directories automatically and just works.
Edit: Corrected find pattern to */.svn instead of .svn, added more details and some other possibilities. However, this depends on your platform and svn version: .svn without */ may be required in some cases, like on CentOS 7.
How about this?
grep -i "search_string" `find "*.some_extension"`
That is halfway solution to finding a search_string within files that have a specific extension....once you know the files that has the string, can be easily modified by piping it into sed....