Ubuntu – Copying certain files by partially matching their names to a list within a text file

command line

I have a directory with files with string names that all start out with 5 numbers (i.e. 12345_a_b, 23456_s_a) and I have a text file within the same directory that has a list of file names named in the same way, however only the numbers match and not anything after the underscore (i.e 12345_q_p, 23456_p_l). I want to copy files in the current directory into a new one, but only those where the first 5 numbers in the name of the file match the first 5 numbers of each filename in the text file, ignoring everything that comes after. It seems like I can use xargs but I'm not sure how to match names partially. Can anyone help?

Best Answer

Iterate over the lines with _ as the IFS, get the desired first portion containing digits, and the copy the files starting with those digits:

shopt -s nullglob
while IFS=_ read -r i _; do [[ $i =~ ^[0-9]{5}$ ]] && echo cp -it dest/ "${i}"*; done <file.txt

Expanded:

#!/bin/bash
shopt -s nullglob  ##Expands to null string if no match while doing glob expansion,
                   ##rather than the literal
while IFS=_ read -r i _; do  ##Iterate over the lines of file.txt, 
                              ##with `_` as the `IFS` i.e. word splitting 
                              ##happens on each `_` only, variable `i` 
                              ##will contain the digits at start; `_` is a
                              ##throwaway variable containing the rest
    [[ $i =~ ^[0-9]{5}$ ]] \ ##Check if the variable contains only 5 digits
      && echo cp -it /destination/ "${i}"*  ##if so, copy the relevant files starting with those digits
done <file.txt

Replace file.txt with the actual source file, and /destination/ with your actual destination directory. Here echo is included to do the dry-run; if satisfied with the commands to be run, just get rid of echo:

shopt -s nullglob
while IFS=_ read -r i _; do [[ $i =~ ^[0-9]{5}$ ]] && cp -it dest/ "${i}"*; done <file.txt