How to pipe the results of 'find' to mv in Linux
LinuxUnixLinux Problem Overview
How do I pipe the results of a 'find' (in Linux) to be moved to a different directory? This is what I have so far.
find ./ -name '*article*' | mv ../backup
but its not yet right (I get an error missing file argument, because I didn't specify a file, because I was trying to get it from the pipe)
Linux Solutions
Solution 1 - Linux
find ./ -name '*article*' -exec mv {} ../backup \;
OR
find ./ -name '*article*' | xargs -I '{}' mv {} ../backup
Solution 2 - Linux
xargs
is commonly used for this, and mv
on Linux has a -t
option to facilitate that.
find ./ -name '*article*' | xargs mv -t ../backup
If your find
supports -exec ... \+
you could equivalently do
find ./ -name '*article*' -exec mv -t ../backup {} \+
The -t
option is a GNU extension, so it is not portable to systems which do not have GNU coreutils
(though every proper Linux I have seen has that, with the possible exception of Busybox). For complete POSIX portability, it's of course possible to roll your own replacement, maybe something like
find ./ -name '*article*' -exec sh -c 'mv "$@" "$0"' ../backup {} \+
where we shamelessly abuse the convenient fact that the first argument after sh -c 'commands'
ends up as the "script name" parameter in $0
so that we don't even need to shift
it.
Probably see also https://mywiki.wooledge.org/BashFAQ/020
Solution 3 - Linux
I found this really useful having thousands of files in one folder:
ls -U | head -10000 | egrep '\.png$' | xargs -I '{}' mv {} ./png
To move all pngs in first 10000 files to subfolder png
Solution 4 - Linux
mv $(find . -name '*article*') ../backup
Solution 5 - Linux
Here are a few solutions.
find . -type f -newermt "2019-01-01" ! -newermt "2019-05-01" \
-exec mv {} path \;**
or
find path -type f -newermt "2019-01-01" ! -newermt "2019-05-01" \
-exec mv {} path \;
or
find /Directory/filebox/ -type f -newermt "2019-01-01" \
! -newermt "2019-05-01" -exec mv {} ../filemove/ \;
The backslash + newline is just for legibility; you can equivalently use a single long line.
Solution 6 - Linux
xargs
is your buddy here (When you have multiple actions to take)!
And using it the way I have shown will give great control to you as well.
find ./ -name '*article*' | xargs -n1 sh -c "mv {} <path/to/target/directory>"
Explanation:
-
-n1
Number of lines to consider for each operation ahead
sh -c
The shell command to execute giving it the lines as per previous condition
"mv {} /target/path"
The move command will take two arguments-
-
The line(s) from operation 1, i.e. {}, value substitutes automatically
-
The target path for move command, as specified
Note: the "Double Quotes" are specified to allow any number of spaces or arguments for the shell command which receives arguments from xargs