hy9fesh
hy9fesh

Reputation: 661

How do I move a file from a directory containing a specific number into a different directory?

I want to move all my files from a folder that have the numbers 1995, 1996, and 1997 to different folders.

Much of what I've found on this list has to do with moving any file that contains any pattern. I want the command to look in the directory, scan the .txt file's contents, and as soon as they find 1996, put it in the 1996 directory.

This means that if the command looks in the directory, scans the .txt file, and finds 1996 on the first line AND finds 1995 on the tenth line, it doesn't put the file in BOTH the 1996 and 1995 folders. I want it to only put the file in the 1996 folder.

grep -rl --null --include '*.txt' 1996 . | xargs -0 sh -c 'cp "$@" /folderpath' sh

This seems to put 1995 files into the 1996 folder just because it contains 1995 somewhere in the file.

Upvotes: 0

Views: 591

Answers (1)

KamilCuk
KamilCuk

Reputation: 140980

I think something like this could work:

find . -name '*.txt' -print0 |
xargs -0 -n1 sh -c '
    if a=$(head -n1 "$1" | grep -o "199[567]"); then
        mv "$1" "./$a"
    fi
' --

Alternatively the xargs can be substituted with while IFS= read -r file; do loop. That would look like:

find . -name '*.txt' -print0 |
while IFS= read -r file; do
    if a=$(head -n1 "$file" | grep -o "199[567]"); then
        mv "$file" "./$a"
    fi
done
  • find finds everything
    • . - in the current directory
    • -name '*.txt' - with names ending with .txt
    • -print0 - and prints them as zero terminated list
  • | - pipe, passes the output of one command to another
  • while - executes a do ... done body until the command returns non-zero exit status
  • IFS= read -r file - a popular mnemonic to read zero separated list, see bashfaq How can I read a file (data stream, variable) line-by-line (and/or field-by-field)?
    • head -n1 "$file" - extract first line from the file
    • grep
      • -o - output the matched string only
      • 199[567] - match 1995 or 1996 or 1997
      • grep outputs a zero exit status if it matches successfully (important at if)
    • a=$(...) - assign the output of the command to a. The exit status of the process substitution $(...) is the last command executed, grep in this case.
    • if command - executes the then ... fi body only if the command returns with a nonzero exit status. Ie. here only if grep matches the string successfully, it will return a zero exit status.
      • mv "$file" "./$a" - the variable a (bad naming...) contains the string that grep matched so it will be 1995 or 1996 or `1997. So move the file to proper folder.

Upvotes: 1

Related Questions