I have a collection of files ( *.zip, *.txt, *.tar.gz, *.doc, …etc ). These files reside within a path. I want to find all the files ( *.txt), then copy, only, the text files that contain specific words ( e.g LINUX/UNIX).
I ran the following:
find . -name "*.txt" | grep 'LINUX/UNIX'
This command was able to find all the text files, then “grep” filtered the resultant text files by listing only the text files that contain ‘LINUX/UNIX’.
How can I copy these final files (i.e. the text files that contain ‘LINUX/UNIX’) to a specific path of choice?
I tried to apply xargs
find . -name "*.txt" | grep 'LINUX/UNIX' | xargs cp <to a path>
But it didn’t work
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Try:
grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0r cp -t /path/to/dest
Because this command uses NUL-separation, it is safe for all file names including those with difficult names that include blanks, tabs, or even newlines.
The above requires GNU cp. For MacOS/FreeBSD, try:
grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0 sh -c 'cp "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="94b0d4">[email protected]</a>" /path/to/dest' sh
How it works:
-
grepoptions and arguments-
-rtells grep to search recursively through the directory structure. (On FreeBSD,-rwill follow symlinks into directories. This is not true of either OS/X or recent versions of GNUgrep.) -
--include '*.txt'tells grep to only return files whose names match the glob*.txt(including hidden ones like.foo.txtor.txt). -
-ltells grep to only return the names of matching files, not the match itself. -
--nulltells grep to use NUL characters to separate the file names. (--nullis supported bygrepunder GNU/Linux, MacOS and FreeBSD but not OpenBSD.) -
LINUX/UNIXtells grep to look only for files whose contents include the regexLINUX/UNIX -
.search in the current directory. You can omit it in recent versions of GNUgrep, but then you’d need to pass a--option terminator tocpto guard against file names that start with-.
-
-
xargsoptions and arguments-
-0tells xargs to expect NUL-separated input. -
-rtells xargs not to run the command unless at least one file was found. (This option is not needed on either BSD or OSX and is not compatible with OSX’sxargs.) -
cp -t /path/to/destcopies the directories to the target directory. (-trequires GNUcp.)
-
Method 2
More portably (POSIX features only):
find . -type f -name '*.txt' -exec grep -q LINUX/UNIX {} ; -exec cp {} /path/to/dest ;
Method 3
The following sh/Bash one liner is another method, though will only work in the current directory, and doesn’t recurse:
for f in ./*.txt; do if grep -l 'LINUX/UNIX' "$f"; then cp "$f" /path/to/dest/; fi; done
The -l option to grep will print a list of the files which are being copied, though you could use -q if you don’t want to see anything on the screen.
Method 4
I am not sure why the original string did not work. Following command works for me.
find / -name (filename*) | grep ‘(filename.extention)’| xargs cp -t ./
In my case filename* is collection of files with same name with different file types (txt, zip, etc). I do grep to find out only filename.txt and copy it to my destination directory (which is currently, ./).
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0