Why wont -exec run? - bash

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.

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

find -exec basename {} vs find -exec echo $(basename {})

I'm sure I'm missing something but I can't figure it out. Given:
$ find -type f
./hello.txt
./wow.txt
./yay.txt
how come the next two commands render different results?
$ find -type f -exec basename {} \;
hello.txt
wow.txt
yay.txt
$ find -type f -exec echo $(basename {}) \;
./hello.txt
./wow.txt
./yay.txt
$(basename {}) is evaluated before the command runs. The result is {} so the command echo $(basename {}) becomes echo {} and basename is not run for each file.
A quick debug on that using the bash -x debugger demonstrated this,
[The example is my own, just for demonstration purposes]
bash -xc 'find -type f -name "*.sh" -exec echo $(basename {}) \;'
++ basename '{}'
+ find -type f -name '*.sh' -exec echo '{}' ';'
./1.sh
./abcd/another_file_1_not_ok.sh
./abcd/another_file_2_not_ok.sh
./abcd/another_file_3_not_ok.sh
And for just basename {}
bash -xc 'find -type f -name "*.sh" -exec basename {} \;'
+ find -type f -name '*.sh' -exec basename '{}' ';'
1.sh
another_file_1_not_ok.sh
another_file_2_not_ok.sh
another_file_3_not_ok.sh
As you can see in the first example, echo $(basename {}) gets resolved in two steps, basename {} is nothing but the basename on the actual file (which outputs the plain file name) which is then interpreted as echo {}. So it is nothing but mimic-ing the exact behaviour when you use find with exec and echo the files as
bash -xc 'find -type f -name "*.sh" -exec echo {} \;'
+ find -type f -name '*.sh' -exec echo '{}' ';'
./1.sh
./abcd/another_file_1_not_ok.sh
./abcd/another_file_2_not_ok.sh
./abcd/another_file_3_not_ok.sh

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))

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

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.

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 -- {} +

Resources