Reputation: 1080
I have a set of files in a Linux directory. I want to copy the files whose names match one of many patterns to a different directory; I'm placing all those pattern in a text file.
What is a possible way I could find all the files with the pattern and copy to a destination folder?
Until now, I was able to do just keep the patterns like this:
find . -type f \( -name "*Patt1* -o -name "*Patt2*" - o -name "*Patt3*" \
-o -name "*Patt4*" -o -name "*Patt5* -o -name "*Patt6*" \) \
| xargs cp {} /home/DestinationFolder/.
My pattern file looks like this:
PYTH
SPYD
ISIN
CUSIP
HELD
SEDO
Upvotes: 0
Views: 5526
Reputation: 52361
You can filter your filenames with grep, using the -f
option to read the patterns from a file:
find . -type f -print0 | grep -zFf pattern.txt \
| xargs -0 -I {} cp {} /home/DestinationFolder
Since your patterns, according to your comment, are just fixed strings, we can add -F
to the grep options to interpret the lines from the input file as fixed strings.
To accommodate any possible character in filenames, I use -print0
to print the filenames null byte separated; grep -z
reads to and writes from a null byte separated stream; and xargs -0
expects null byte separated input.
Upvotes: 1
Reputation: 1
I am on MacOS. My problem was very similar you yours, but I wanted to use a regex to match the files to be operated on. The first answer pointed me in the right direction, but sadly (or not?) I am on MacOS. Evidently, BSD find
doesn't like -printf
, and BSD grep
doesn't like -z
. So, fiddlesticks.
On MacOS (10.13: High Sierra), and using bash (I tested the MacOS-supplied one and GNU bash 4.4.19), the following does what you need. As a bonus, it's resilient with respect to filenames that contain spaces (but not all weird filenames), and allows patterns to be extended regexs instead of only simple fixed strings. The example below includes an extended regex pattern (the first line in the file) which I actually used to do a similar operation: moving files that end in patterns like _9.mpg to a different directory:
Caveat: To make spaces play nice for files with spaces in them (and who doesn't have spaces in their filenames, eh??), I'm using this hack, which will cause bash to split pipes between commands on newlines, instead of spaces:
OLD_IFS=$IFS
IFS=$(echo -en "\n\b")
Here is a test "source" directory:
% ls -1 source
bad dog_1.mp3
bod dog.mp3
i am SEDO yeah
Here is the empty "target" directory:
% ls ../target|wc -l
0
You can make a pattern file containing whatever patterns are legal extended regexs, which includes simple strings which don't contain special regex characters. If you revile regexs and want just simple strings (and are therefore more sane than I), change 'grep -Ef' above to 'grep -f':
% cat patterns.txt
_\d+\.m..$
PYTH
SPYD
ISIN
CUSIP
HELD
SEDO
Here is the file with the meat:
% cat generate-commands.sh
for f in $(find ${src} -type f | grep -Ef ${pats}); do
echo mv \"$f\" \"${trg}/$f\"
done
And here we go! First, cd into the source dir, then run the generate-commands file with the required params:
% cd source
% src=. trg=../target pats=../patterns.txt . ../generate-commands.sh
mv "./i am SEDO yeah" "../target/./i am SEDO yeah"
mv "./bad dog_1.m4v" "../target/./bad dog_1.m4v"
Then, ever so carefully, thoughtfully consider actually executing the commands that were output by the generate-commands.sh script.
Finally, unless you like surprises, it's probably a good idea to either either kill your current shell, or do this:
IFS=$OLD_IFS
Upvotes: 0