Find and replace with sed in directory and sub directories except few directories - shell

I want to replace foo with bar in a directory structure but I want to skip few folders
I am using this command:
find ./ -type f -exec sed -i -e 's/foo/bar/g' {} \;

You -prune to skip directory:
find . -type f -o \
\( \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) \
-exec sed -i -e 's/foo/bar/g' {} \;
... or use -path ./path/to/your-dir instead of -name unwanted-dir if you want to match full path of the unwanted directory...

find . -type f -o \
\( \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) \
-exec sed -i -e 's/foo/bar/g' {} \;
This is not working because it's equivalent to
find . -type f -o \
\( \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) -and \
-exec sed -i -e 's/foo/bar/g' {} \;
since -and is assumed where the operator is omitted and -and has higher precedence than -o, so the -exec is never evaluated.
It works if the -type test is inside the outer parentheses:
find . \( -type f -o \
\( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -false \) \
-exec sed -i -e 's/foo/bar/g' {} \;
or, with fewer parentheses:
find . \( -name unwanted-dir1 -o -name unwanted-dir2 \) -prune -o \
-type f -exec sed -i -e 's/foo/bar/g' {} \;
or without parentheses as David C. Rankin suggested in his comment.

Related

find -print0 with 2 files only shows 1

As an example, I have two files in my directory:video.mp4 and video.webm
If I use:
find . -maxdepth 1 -type f -iname "*.mp4" -o -iname "*.webm"
I got correctly:
/video.webm
./video.mp4
But if I add -print0, that I need to pipe to parallel I got:
./video.webm
What I'm doing wrong?
Assuming your print0 attempt looks like:
find . -maxdepth 1 -type f -iname "*.mp4" -o -iname "*.webm" -print0
The -print0 is processed with the 2nd -iname option, in effect:
find . -maxdepth 1 -type f -iname "*.mp4" -o ( -iname "*.webm" -print0)
One option would be to add explicit parens to insure the -print0 is applied against both -iname options, eg:
find . -maxdepth 1 -type f \( -iname "*.mp4" -o -iname "*.webm" \) -print0

Change the default cursor position of find-grep command in emacs

I changed default find-grep command
(helped by this answer).
my init.el is following.
(grep-apply-setting 'grep-find-command "find . -type d \\( -name '.git' \\) -prune -o -type f -exec grep -nH -e \\{\\} +")
and then I execute find-grep, I get minibuffer and cursor is at end of line.
I want to change default cursor position to after -e
find . -type d \( -name '.git' \) -prune -o -type f -exec grep -nH -e (*here*) \{\} +
is this possible?
thanks.
Change the code in your init.el to the following:
(grep-apply-setting 'grep-find-command '("find . -type d \\( -name '.git' \\) -prune -o -type f -exec grep -nH -e \\{\\} +" . 72))

Need help omitting folders in find command

I have this line in a script I'm writing
find / \( -perm -4000 -o -perm -2000 \) -type f -exec file {} \; | grep -v ELF | cut -d":" -f1 >> $OUTPUT
It does the work, BUT I always get these messages I want to omit
find: `/proc/29527/task/29527/fd/5': No such file or directory
find: `/proc/29527/task/29527/fdinfo/5': No such file or directory
find: `/proc/29527/fd/5': No such file or directory
find: `/proc/29527/fdinfo/5': No such file or directory
How can I omit the /proc directory?
I believe this should work:
find / -path /proc -prune -o \( -perm -4000 -o -perm -2000 \) -type f ...
^^^^^^^^^^^^^^^^^^^^^ Add this to your command line
What if you redirect STDERR to /dev/null. That way, you don't see the unwanted error/warning in your TTY (STDOUT) like
{ find / \( -perm -4000 -o -perm -2000 \) -type f -exec file {} \; | grep -v ELF | cut -d":" -f1 >> $OUTPUT; } 2>/dev/null
The following prunes the proc directory:
find / -name /proc -prune -o \
\( -perm -4000 -o -perm -2000 \) -type f \
-exec file {} \; | grep -v ELF | cut -d":" -f1 >> $OUTPUT

Bash - find and remove all html files but a selected ones

I'd like to do is delete all the html files recursively, omitting template.html and list.html?
So far I have the following code but I don't know how set these 2 file name exceptions.
find . -name "*.html" -exec rm -rf {} \;
You can do it with !
find . -type f \( -iname "*.html" ! -iname "template.html" ! -iname "list.html" \) -exec rm -rf {} \;
Use -not:
find . -name "*.html" -not -name template.html -not -name list.html -exec rm -rf {} \;
Try the following:
find . -type f -iname \*.html ! -iname template.html ! -iname list.html -exec rm -f -- {} +

Why wont -exec run?

I am using the below script as a clean up script. The find sections returns the correct results, but for some reason the -exec section doesn't run.
find /users/rhysparker/downloads/ -maxdepth 1 -iname \*.pkg -o -iname \*.app -o -iname \*.dmg -exec mv {} /folder/location/ \;
Any help would be appreciated.
The -o operation has low precedence, so your -exec is bound exclusively to the *.dmg test. Use parentheses to group the statement properly. (And quote them so the shell passes them through to find).
find /users/rhysparker/downloads/ -maxdepth 1 \( -iname \*.pkg -o -iname \*.app -o -iname \*.dmg \) -exec mv {} /folder/location/ \;
In expr1 -o expr2, if expr1 is true, the expr2 will not be evaluated.
In your command:
-iname \*.pkg OR
-iname \*.app OR
-iname \*.dmg AND -exec mv {} /folder/location/ \;
If one of the first two is true, the last will not be evaluated. So you have to use () to change the expr:
find /users/rhysparker/downloads/ -maxdepth 1 \( -iname \*.pkg -o -iname \*.app -o -iname \*.dmg \) -exec mv {} /folder/location/ \;
Now, it becomes:
(-iname \*.pkg OR -iname \*.app OR -iname \*.dmg) AND
-exec mv {} /folder/location/ \;
This ensure the -exec will be evaluated when the files is found.

Resources