grep filenames matching a pattern and move to desi

2019-07-15 12:22发布

I have a list of patterns in a .txt file. [list.txt]. Foreach line in list.txt, I want to find all the files at a location which begin with the specified pattern in list.txt, and then move these files to another location. Consider an example case.

at ~/home/ana/folder_a I have list.txt, which looks like this...

list.txt

1abc
2def
3xyz

At this location i.e /home/ana/folder_a/, there are multiple files which are beginning with the patterns in list.txt. So, there are files like 1abc_a.txt, 1abc_c.txt, 1abc_f.txt, 2def_g.txt, 3xyz_a.txt

So what I want to achieve is this:

for i in cat list.txt; do 
  ls | grep '^$i' [thats the pattern] | 
  mv [files containing the pattern] to /home/ana/folder_b/

Please note that at the other location, i.e /home/ana/folder_b/ I have already created directories, specific for each pattern.

So /home/ana/folder_b/ contains subdirectories like 1abc/ , 2def/ , 3xyz/ In effect, I wish to move all the files matching pattern '1abc', '2def' and '3xyz' from /home/ana/folder_a/ to their respective sub-directories in /home/ana/folder_b/, such that /home/ana/folder_b/1abc will have 1abc_a.txt , 1abc_c.txt , and 1abc_f.txt ; /home/ana/folder_b/2def/ will have 2def_g.txt and /home/ana/folder_b/3xyz/ will have 3xyz_a.txt

3条回答
够拽才男人
2楼-- · 2019-07-15 12:46

i'd suggest using the -exec action of find to call mv in your loop.

beginning file structure: (as you can see, i'm calling this from the parent of folder_a and folder_b)

$ find
.
./folder_a
./folder_a/1abc_a.txt
./folder_a/1abc_c.txt
./folder_a/1abc_f.txt
./folder_a/2def_g.txt
./folder_a/3xyz_a.txt
./folder_b
./folder_b/1abc
./folder_b/2def
./folder_b/3xyz
./list.txt

$ cat list.txt
1abc
2def
3xyz

command:

while read pattern
 do 
  find ./folder_a -type f -name "$pattern*" -exec mv "{}" "./folder_b/$pattern" \;
 done <list.txt

alternate command (same thing, just all on one line):

while read pattern; do find ./folder_a -type f -name "$pattern*" -exec mv "{}" "./folder_b/$pattern" \;; done <list.txt

resulting file structure:

$ find
.
./folder_a
./folder_b
./folder_b/1abc
./folder_b/1abc/1abc_a.txt
./folder_b/1abc/1abc_c.txt
./folder_b/1abc/1abc_f.txt
./folder_b/2def
./folder_b/2def/2def_g.txt
./folder_b/3xyz
./folder_b/3xyz/3xyz_a.txt
./list.txt
查看更多
倾城 Initia
3楼-- · 2019-07-15 13:02

Grep's -f option matches patterns from a file so you don't have to loop over each line in the file in shell:

$ ls                              # List all files in dir, some match, some don't
1abc_a.txt 1abc_c.txt 1abc_f.txt  2def_g.txt 3xyz_a.txt file1 file2 list.txt

$ cat list.txt                    # List patterns to match against 
1abc
2def
3xyz

$ ls | grep -f list.txt           # grep for files that only match pattern
1abc_a.txt
1abc_c.txt
1abc_f.txt
2def_g.txt
3xyz_a.txt

Pipe to xargs to do the move:

ls | grep -f list.txt | xargs -i -t mv {} ../folder_B
mv 1abc_a.txt ../folderB 
mv 1abc_c.txt ../folderB 
mv 1abc_f.txt ../folderB 
mv 2def_g.txt ../folderB 
mv 3xyz_a.txt ../folderB 

Edit: Realised I missed the subdirectory part of the question, @Thor's answers is the best approach for this, still I think you might find some use from this answer.

查看更多
一夜七次
4楼-- · 2019-07-15 13:07

I think glob expansion is the way to go here:

while read pattern; do
  mv "${pattern}"* ../folder_b/"$pattern"
done < list.txt

Start with an echo in front of the mv command, and remove it when you're happy with the output.

查看更多
登录 后发表回答