Delete a list of file/directory names - bash

I have a list of file and directory names:
foo.js FOOBAR bar.json fubar/ .foo/ .baz
Is there a way to pass them to find, grep or something and delete all with one command?

Why not just use rm?
rm -fr -- foo.js FOOBAR bar.json fubar/ .foo/ .baz
-- is optional if one of your file arguments starts with -.
If you want to recursively delete files with those filenames recursively, you can do this:
find path \( -name foo.js -o -name FOOBAR -o -name bar.json -o -name fubar -o -name .foo -o -name .baz \) -exec rm -fr -- '{}' \;
Similarly with xargs:
find path \( -name foo.js -o -name FOOBAR -o -name bar.json -o -name fubar -o -name .foo -o -name .baz \) -print0 | xargs -0 rm -fr --

You can simply use:
rm -rf foo.js FOOBAR bar.json fubar/ .foo/ .baz.
-r option will remove those files recursively and -f option will remove those files forcefully.
If all the files are in same folder then rm -rf * will do the job!

Related

find works, but find -exec doesn’t

I am trying to find all images in subfolders of a given folder, and move them somewhere else. I have tried the following in zsh (my default) and sh (what most tutorials seem to be using) on a Mac running OS X 10.9.3.
This prints out all the images in the subfolders of $someDir:
find "$someDir" -iname \*.jpg -o -name \*.png -o -name \*.gif
However, when I want to pass those images to another command, I can’t get it to work. As an exercise, I tried it with echo:
find "$someDir" -iname \*.jpg -o -name \*.png -o -name \*.gif -exec sh -c "echo hello {}" \;
It just returns silently, and the value of $? is 0.
I eventually want to do something along these lines:
find "$someDir" -iname \*.jpg -o -name \*.png -o -name \*.gif -exec sh -c "mv {} $destination" \;
But I can‘t even get the echo example to work. What am I doing wrong?
You need to put parentheses around all the name tests:
find "$someDir" \( -iname \*.jpg -o -name \*.png -o -name \*.gif \) -exec sh -c "echo hello {}" \;
Otherwise, the -exec is only done for files that match *.gif.
When you leave out the action, there's a default -print in each branch of the -o. But if there's any action option in the command, there's no default actions anywhere.
These should work (make sure $destination is defined)
find "$someDir" \( -iname \*.jpg -o -name \*.png -o -name \*.gif \) -exec echo hello {}
find "$someDir" \( -iname \*.jpg -o -name \*.png -o -name \*.gif \) -exec mv {} $destination \;

Bash find -exec cp not all files are copyed

I am writing a bash script to find image files and to copy them to a dir. My problem is when I use find it finds all files but when I add
-exec cp -n {} $2 \;
I know that I have set do not clobber but my test case takes this into account I also have a renaming mechanism in place later in the script that is tried and tested.
When I enter straight in terminal I get same problem
find Desktop -iname '*.JPG' -o -iname '*.jpeg' -o -iname '*.jf[il1]f' -o -iname '*.exif' -o -iname '*.tiff' -o -iname '*.gif' -o -iname '*.bmp' -o -iname '*.png'
I get (my test case 300 images in different dir with duplicates and same named file but for this problem simplified to these files on my desktop)
Desktop/IMG_0316.PNG
Desktop/IMG_0191.JPG
Desktop/IMG_0292.JPG
Desktop/IMG_0269.PNG
Desktop/IMG_0318.PNG
Desktop/IMG_0172.JPG
when I add cp command
find Desktop/ -iname '*.JPG' -o -iname '*.jpeg' -o -iname '*.jf[il1]f' -o -iname '*.exif' -o -iname '*.tiff' -o -iname '*.gif' -o -iname '*.bmp' -o -iname '*.png' -exec cp -n {} test \;
The only files I get in test are
Desktop/IMG_0316.PNG
Desktop/IMG_0269.PNG
Desktop/IMG_0318.PNG
I have tried removing -n from cp but made no diffrence
Thanks any help is appreciated
If I add echo I get
cp -n Desktop/IMG_0316.PNG test
cp -n Desktop/IMG_0269.PNG test
cp -n Desktop/IMG_0318.PNG test
Use parens
find Desktop/ \( -iname '*.JPG' -o -iname '*.jpeg' -o -iname '*.jf[il1]f' -o -iname '*.exif' -o -iname '*.tiff' -o -iname '*.gif' -o -iname '*.bmp' -o -iname '*.png' \) -exec cp -n {} test \;
Actually, -exec is an action while -iname is a predicate (a test in terms of man find). They aren't interchangeable at all. Default action is -print. So your expression means:
find Desktop -iname '*.JPG' -print \
-o -iname '*.jpeg' -print -o ... -o -iname -iname '*.png' -exec cp...
By using parens your group tests and the provide a single action for the entire group.

Why is this command exploding

So I got this as an answer to a previous question as an answer for looking recursively through files in a directory and deleting the files and directories if found:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -exec rm -rf "{}" \;
There are two problems with this:
One:
find: `./adam.balan/AisisAjax/.git': No such file or directory
because of this error the rest of the script doesn't execute. Now I don't want to have to check for any of the files or folders. I don't care if they exist or not, I want to suppress the error on this.
The second is that I am also getting the error on a directory that needs to be excluded from this search: vendor/
find: `./vendor/adam.balan/AisisAjax/.git': No such file or directory
I do not want it searching vendor. I want it to leave vendor alone.
How do I solve these two problems? Suppression and ignoring.
The problem is that you're deleting a directory that find then tries to descend into. You can use -prune to prevent that:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \;
To ignore all errors, you can use 2> /dev/null to squash the error messages, and || true to avoid set -e making your script exit:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \; 2> /dev/null || true
Finally, to avoid descending any directory named 'vendor', you can use -prune again:
find -name vendor -prune -o \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \; 2> /dev/null || true

Handling spaces in a directory in bash sh

I have this line cp $(find "$directory" -type f | grep -iE '\.(c|cc|cpp|cxx)$') ~/src which searches a given directory (in this case, $directory is /home) and copies all file with the extensions of .c, .cc, .cpp and .cxx into the src folder, but I get an error of cp:cannot stat directory: No such file or directory.
I thought putting the directory in quotes would prevent that. What am I doing wrong?
The error is from the command cp, so quoting $directory, while generally a good idea, won't help you solve this error.
Your construct will fail with file/directory names that contain spaces, cases where grep turns out with zero matches, and probably other cases I can't think of right now.
Some better solutions:
Use find's name matching instead of grep, and use -exec with it:
find "$directory" -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.cxx' \) -exec cp '{}' ~/src ';'
find "$directory" -type f -regextype posix-egrep -iregex '.*\.(c|cc|cpp|cxx)$' -exec cp '{}' ~/src ';'
Use xargs with \0 separators instead of \n:
find "$directory" -type f -print0 | grep -z -iE '\.(c|cc|cpp|cxx)$' | xargs -0 -I{} cp "{}" ~/src
If your file structure is flat (no subdirectories), just use cp:
cd "$directory"; cp *.c *.cc *.cpp *.cxx ~/src

Find and delete multiple argument directories

Say I have 3 directories .git, .hg and .svn somewhere in the folder called lol.
How can I find and remove all of these?
The following does so only for the last one (.svn):
$ find lol -type d -name .git -o -name .hg -o -name .svn -delete
E: This could be done with ls too but not without shopt -s globstar (since I'm not doing it with zsh):
$ shopt -s globstar
$ rm -r $(ls -d ceaw/**/.{git,hg,svn})
E2: Another solution woulda been:
$ find lol -type d -name .git -o -name .hg -o -name .svn | xargs rm -rf
Try using the -exec option instead.
find lol -depth -type d \( -name .git -o -name .hg -o -name .svn \) -exec rm -r '{}' \;

Resources