Joao  Vitorino Joao Vitorino - 1 month ago 13
Bash Question

Rename file and keep the extension in bash

I have to rename some files that I don't exactly know where they are and keep their extensions.

Ex: files system-2.1.3.war, system-2.1.3.ear, system-2.1.3.ejb
to system.ear, system.war,system.ejb

So I wrote this.

find /DIR1 -name "*.ear" -o -name "*.war" -o -name "*.ejb" \
-exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' \;


The problem is: It works only for the last file in the "or list" of "find" command. So if the file is system-2.1.3.ejb, works, for system-2.1.3.war and system-2.1.3.ear don't.

If I change the find to

find /DIR1 -name "*.ejb" -o -name "*.war" -o -name "*.ear"


Notice that *.ear now is the last one, it will work for system-2.1.3.ear and not for the others and so on.

Please help me to fix this.

I know I can create a script to accomplish that but I want a "one line" code.

Answer

Rather than embedding the {} in the script, pass it as an argument:

find /DIR1 \( -name "*.ear" -o -name "*.war" -o -name "*.ejb" \) \ 
  -exec sh -c 'ext=${1##*.}; cp "$1" "NEW_NAME.$ext"' _ '{}' \;

Without the \(...\) grouping, -exec only applies to the primary it is implicitly "and"ed with, the previous one.

You can also limit the number of calls to the shell by looping over multiple arguments:

find /DIR1 \( ... \) -exec sh -c 'for f; do ext=${f##*.}; cp "$f" "NEW_NAME.$ext"; done' _ {} +