11

How can I move files in a folder with a specific pattern to the destination folder?

I want to move files with names in the range [00-09] in the 4th column when separated by delimiter "-".

ls | cut -d "-" -f 4 | grep ^[00-09]

Shows these files:

UNCID_376947.TCGA-DD-A118-01A-11R-A131-07.110525_UNC12-SN629_0087_BC03HWABXX.7.trimmed.txt
UNCID_377115.TCGA-CC-5263-01A-01R-A131-07.110525_UNC12-SN629_0087_BC03HWABXX.5.trimmed.txt
UNCID_377252.TCGA-DD-A114-11A-12R-A131-07.110525_UNC12-SN629_0087_BC03HWABXX.6.trimmed.txt
fedorqui
  • 9,909
  • 1
  • 23
  • 41
r.bot
  • 113
  • 1
  • 1
  • 5

2 Answers2

17

Use a glob expression:

mv your_dir/*?-*?-*?-0[0-9]* new_dir/

To test it, you can firstly perform a ls your_dir/*?-*?-*?-0[0-9]* to make sure it matches the files you want.

The expression *?-*?-*?-0[0-9]* means: characters + - three times and then 0 and any character.

Test

$ ls
another_dir/  aa-03A-b  aa-b-03A-b  aa-b-c-03A-b  a-b-c-03A-b  a-b-c-23A-b
$ mv *?-*?-*?-0[0-9]* another_dir/
$ ls another_dir/
aa-b-c-03A-b  a-b-c-03A-b
steeldriver
  • 131,985
  • 21
  • 239
  • 326
fedorqui
  • 9,909
  • 1
  • 23
  • 41
2

You can use a 'for loop':

for FILE in 'file-list'
do
  echo "$FILE"
  mv "$FILE" /your/destination/
done

Explanation:

'file-list' should be replaced with a method to get a list of the files you want to use. For example $(cat files.txt) if you already have a list in a file, pattern* if the files in your directory start with the same pattern or $(find -iname "*pattern*") if you want to use find to get the list.
The output will be stored in the variable FILE one element after the other. The the commands between do and done are executed for each element. You can use echo "$FILE" to check if your command matches the right files before adding the mv command to the loop.

Wayne_Yux
  • 4,873
  • 3
  • 27
  • 35
  • I like the idea of using a `for` loop, so that you may have more control over what you are doing. However, `for FILE in $(expression)` may be a bit redundant: first, because parsing `ls` is not recommended; secondly, because you can directly say `for file in expression*` instead of expanding the result. That is, you better say `for file in *` than `for file in $(ls)`. – fedorqui Oct 20 '15 at 10:14
  • 1
    Yes, you are right. I tried to keep it a bit more general, because your answer already provides a good specific solution for the asker. Maybe a `find` command would also be a good idea in OPs case to get a file list – Wayne_Yux Oct 20 '15 at 10:18
  • About your update: instead of `for name in $(cat file)`, it is way more preferred to say `while read -r name; do ... done < file`. Or if you want to feed with a `find` result, `while read -r name; do ... done < <(find ...)`. – fedorqui Oct 20 '15 at 10:32
  • Yeesh, maybe this works if you have a file listing all the filenames, but that's not what the question asked, and this 'solution' led me down a serious rabbit hole of parsing problems with `ls` and `find`. At least in some circumstances, you cannot use `find` as claimed here, it seems to produce `??` as the filename. Not sure exactly what specifics are causing this and I'd rather spend time googling for a solution that works in my case than troubleshooting this one, so, not really sure what the problem is, but this definitely isn't a generalized solution. – John Smith Mar 09 '21 at 00:34