Batch copy and rename with regexp

cprename

I am wondering whether there is a way how to copy and rename a bunch of files without scripting. I have files with names like prefix_12345678901_12345678901_suffix.ext and I need to copy all of them into a given directory such that the copies are named like 1234567890_1234567890.ext

I also do not want to overwrite existing files in the target directory.

I know I could do something like:

cp -n source/*.ext target

followed by

rename 's/.*([0-9]{11}_[0-9]{11}).*\.(.*$)/$1.$2/' *.ext

but this would make copies first and only then figured out whether the files already exist or not. I need sort of a reversed process…

EDIT:

Well, I guess this is scripting, but I finally suceeded with something like:

for i in /source/*.ext; do if [[ "$i" =~ [0-9]{11}_[0-9]{11} ]]; then cp $i /target/${BASH_REMATCH[0]}.ext; fi done;

Best Answer

pax can copy and rename all at once.

pax -rw -pp -k \
    -s'!^source/[^/]*\([0-9]\{11\}_[0-9]\{11\}\)[^/]*\(\.[^./]*\)!\1\2!' \
    -s'!.*!!' source target

pax -rw copies files; -pp preserves permissions, and -k says not to overwrite existing files. The -s arguments tell pax to rename files as it's copying. The first transformation makes the renaming you want (using basic regular expressions and substitutions like in ed). The second transformation turns every source file name that's not yet matched into the empty string, which tells pax not to copy that file.

Note to zsh fans: as far as I can tell, you can't get zmv to copy the files where the definition doesn't exist and leave the others alone.

Related Question