how do you grep the contents of all files in a directory for "TEST" then move those files to a different directory(like the home dir.)?
3 Answers
You can combine grep and find for this task:
find SOURCE -maxdepth 1 -type f -exec grep -q TEST {} \; -exec mv -i {} DEST \;
How it works
find SOURCE -maxdepth 1 -type f
finds all files (-type f
) in the directory SOURCE.If you want to include files in subdirectories as well, just remove
-maxdepth 1
.-exec grep -q TEST {} \;
greps the files, one by one, for the string TEST. Here,{}
is the file that is currently being processed.The
-q
switch makes grep "quiet", i.e., it will not output anything. The-exec
statement will be true if grep is successful, i.e., it finds the string.-exec mv -i {} DEST \;
moves a file containing the string TEST into the directory DEST.The
-i
switch make mv "interactive", i.e., it will prompt before overwriting other files.
-
I have never thought of being able to chain
-exec
like that, so I have learned something today, even though it is still early where I am :-) . Mar 6, 2014 at 8:41
Just another alternative (this requires some GNU specific extensions, though; since you tagged the question "Unix", it might not fit you):
grep -lZd skip TEST SOURCE/* | xargs -0I{} mv -i {} DEST
grep -l
prints matching filenames instead of normal output.
grep -Z
gives null byte separated output, which is a safe bet in handling strange filenames over pipes.
grep -d skip
defines the
skip
action for encountered directories among the input arguments.This is not really needed; it just avoids the notice
grep: SOURCE/DIR: Is a directory
when encountering directories. If you want recursive reading of files in directories, use the actionrecurse
, or even shorter just the equivalent-r
switch (see below point as well).SOURCE/*
matches all files in the directory
SOURCE
using shell globbing. Hidden files are per default not matched; this can be changed by settingshopt -s dotglob
in Bash before thegrep
command is issued.One might be tempted to just add
SOURCE/.*
to the input arguments, but this will have perhaps unexpected consequences if used with-r
(since we match.
and..
as well).If recursive matching is wanted, just use
-r SOURCE
without file globbing as the input argument, which includes hidden files in the directory structure.xargs -0
interprets the input as null separated.
xargs -I{}
defines
{}
to be a placeholder for the input argument.mv -i
makes the move interactive as per Dennis' suggestion, to avoid mistakes.
To test this pattern (or commands in general), a useful technique is to insert echo
before the actual command to see which commands are to be executed, i.e. change mv
to echo mv
.
$ mv TEST* /path/to/destination
Works for me, hope it works for you. In my case it was:
$ mv note_[5,6]* ~/documents/notes
Which moved note_5_math.pdf and note_6_math.pdf to home/documents/notes directory.
-
1
-
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.– Community BotJun 17, 2023 at 6:27
-
They want to move files that contain the string
TEST
, (re)read the question.– TotoJun 17, 2023 at 8:04