1

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 3

3

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.

1
  • 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
2

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 action recurse, 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 setting shopt -s dotglob in Bash before the grep 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.

0

$ 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.

3
  • 1
    Hello, this has nothing to do with grep.
    – Destroy666
    Jun 17, 2023 at 6:27
  • 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 Bot
    Jun 17, 2023 at 6:27
  • They want to move files that contain the string TEST, (re)read the question.
    – Toto
    Jun 17, 2023 at 8:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .