Shell Scripting: Using bash with xargs - bash

I'm trying to write a bash command that will delete all files matching a specific pattern - in this case, it's all of the old vmware log files that have built up.
I've tried this command:
find . -name vmware-*.log | xargs rm
However, when I run the command, it chokes up on all of the folders that have spaces in their names. Is there a way to format the file path so that xargs passes it to rm quoted or properly escaped?

Try using:
find . -name vmware-*.log -print0 | xargs -0 rm
This causes find to output a null character after each filename and tells xargs to break up names based on null characters instead of whitespace or other tokens.

Do not use xargs. Find can do it without any help:
find . -name "vmware-*.log" -exec rm '{}' \;

Check out the -0 flag for xargs; combined with find's -print0 you should be set.
find . -name vmware-*.log -print0 | xargs -0 rm

GNU find
find . -name vmware-*.log -delete

find . -name vmware-*.log | xargs -i rm -rf {}

find -iname pattern
use -iname for pattern search

To avoid space issue in xargs I'd use new line character as separator with -d option:
find . -name vmware-*.log | xargs -d '\n' rm

Related

Removing all the files with a specific extension using bash

I want to remove all the files with '*.tar.gz' extension using a bash command.
I tried the following, but it didn't work.
find . -iname '*.tar.gz' | rm
Could you please suggest which command should I use in this case?
Also, could you please tell me why the above command doesn't work?
find itself can delete in some versions, so :
find . -iname '*.tar.gz' -delete
if you don't have this switch, use anubhava's solution.
Don't pipe rm to output of find output, use xargs or find -exec:
find . -iname '*.tar.gz' -exec rm {} +
OR:
find . -iname '*.tar.gz' -print0 | xargs -0 -I {} rm {}

how to grep for "/local" in all perl files in current directory

I am using the following command to grep for string "/local" in all .pl files,can anyone point what is wrong here?
find . *.pl| xargs grep '/local' -sl
Pass -name argument, and quote *.pl:
find . -name "*.pl" | xargs grep '/local' -sl
Why is everyone suggesting "find"? The shell can work out your ".pl" files for you:
grep "/local" *.pl
You could just as easily
find . -type f -name '*.pl' -exec grep '/local/' {} \;
Or a more optimal form if your find supports it, this passes multiple files to grep at a time
find . -type f -name '*.pl' -exec grep '/local/' {} +
-exec tends to be slow.
I'm partial to:
find . -name "*.pl" -print0 | xargs -0 grep -sl '/local'
...because it isn't confused by filenames with newlines in them.
Note however that some versions of GNU grep appear to have a memory leak that is triggered by grep commands with a very long list of filenames to search. Under such circumstances, -exec is more reliable.

Move only mp3s within multiple directories to a single folder

This solution from SO works but unfortunately some of my mp3s have quotes (') in their names which results in the following error:
xargs: unterminated quote
Is it possible to adapt the following command to allow it to copy all mp3s, regardless of the quotes in their file name?
find . -name "*.mp3" | xargs -I {} cp -iv "{}" /my/dir
Thank you.
Try adding -print0 to find and -0 to xargs.
find . -name "*.mp3" -exec cp -iv {} /my/dir \;

Getting error "xargs unterminated quote" when tried to print the number of lines in terminal

I want to get the number of lines in my application. I am using this code:
find . "(" -name "*.m" -or -name "*.h" ")" -print | xargs wc -l
It is working fine in other applications but for one of my applications it is giving the error "xargs unterminated quote".
Does one of your filenames have a quote in it? Try something like this:
find . "(" -name "*.m" -or -name "*.h" ")" -print0 | xargs -0 wc -l
The -print0 argument tells find to use the NULL character to terminate each name that it prints out. The -0 argument tells xargs that its input tokens are NULL-terminated. This avoids issues with characters that otherwise would be treated as special, like quotes.
This can happen because you have a single quote in a filename somewhere...
i.e., -> '
To find the problem file, run the following in the terminal:
\find . | grep \'
you can also run xargs like so to effectively address this issue:
xargs -I
and it can also happen if you have an alias for xargs setup that's causing an issue. To test if this is the case, just run xargs with a \ in front of it, e.g.
\find . | \xargs ....
The \ simply means "run the command without any aliases"
The canonical way to solve quotes, spaces and special characters problems when using find is to use the -exec option instead of xargs.
For your case you can use:
find . "(" -name "*.m" -or -name "*.h" ")" -exec wc -l "{}" \;
After some tinkering, I found that this command worked for me (because I had spaces and unmatched quotations in my filenames):
find . -iname "*USA*" -exec cp "{}" /Directory/to/put/file/ \;
. refers to the location the search is being run
-iname followed by the expression refers to the match criteria
-exec cp "{}" /Directory/to/put/file/ \; tells the command to execute the copy command where each file found via -iname replaces "{}"
You need the \; to denote to the exec command that the cp statement is ending.
Solved by replacing from source " with \"

Better way to limit the unix command find by filename

I'm getting results using find with filenames that have '~' and .swp, etc. So I did the following, but is there a better way to do this? The '.*.js' -iname '*.js' part feels "redundant".
$ find ./ '.*.js' -iname '*.js' -print0 | xargs -0 grep -n ".*loginError.*"
find: `.*.js': No such file or directory
./js/signin.js:252: foo.loginError();
./js/signin.js:339:foo.loginError = function() {
./js/signin.js:340: foo.log("ui.loginError");
Try using
find . -name \*.js -print0 | xargs -0 grep -n ".*loginError.*"
That will find only files with 'js' extension and not ending in ~ or .swp
EDIT: Added '0' -print0 (edit requires 6 characters so I'm adding this; ergh!)
To do it all in one command without the xargs you could do it like this
find . -name "*.js" -exec grep -n ".*loginError.*" /dev/null {} \;
the /dev/null piece is to make grep think it's searching multiple files and then it'll output the filename correctly, otherwise it'd just print out the line number without telling you which file it's in

Resources