0

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.

4 Answers 4

3

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' _ {} + 
Sign up to request clarification or add additional context in comments.

2 Comments

I add ( an ) to my code and works, thanks. But why you use "_ '{}'" if cp "$1" "NEW_NAME.$ext" already do the job?
The argument to -c is the script to execute, but you still have to pass arguments for $1 to expand to. This makes it easier to ensure any arguments passed to cp are properly quoted.
3

try this;

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

or

find ./DIR1/ -regex '.*\(.ear\|.war\|.ejb\)$' -exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' \; 

Eg;

user@host $ ls -arlt DIR1/ total 76 -rw-rw-r-- 1 user user 0 Oct 21 22:59 system-2.1.3.war -rw-rw-r-- 1 user user 0 Oct 21 22:59 system-2.1.3.ear -rw-rw-r-- 1 user user 0 Oct 21 22:59 system-2.1.3.ejb drwxrwxr-x 2 user user 4096 Oct 21 22:59 . user@host $ find . \( -name "*.ear" -o -name "*.war" -o -name "*.ejb" \) -exec bash -c 'export var1={}; cp $var1 NEW_NAME${var1: -4}' \; user@host $ ls -ralt total 76 -rw-rw-r-- 1 user user 0 Oct 21 22:59 system-2.1.3.war -rw-rw-r-- 1 user user 0 Oct 21 22:59 system-2.1.3.ear -rw-rw-r-- 1 user user 0 Oct 21 22:59 system-2.1.3.ejb drwxrwxrwt 11 root root 69632 Oct 21 23:10 .. -rw-rw-r-- 1 user user 0 Oct 21 23:10 NEW_NAME.war -rw-rw-r-- 1 user user 0 Oct 21 23:10 NEW_NAME.ear -rw-rw-r-- 1 user user 0 Oct 21 23:10 NEW_NAME.ejb drwxrwxr-x 2 user user 4096 Oct 21 23:10 . 

Comments

2

If you have rename utility then you can avoid forking BASH subprocess for each file and also make use of regex feature in find to avoid multiple -name options:

find /DIR1 -regextype awk -regex '.*\.([we]ar|ejb)$' \ -exec rename 's/.*(\.[^.]+)$/system$1/' '{}' + 

Comments

1

I'd use a while:

find . -name "*.war" -o -name "*.ejb" -o -name "*.ear" | while read file; do cp $file NEW_NAME${file: -4}; done 

Keep in mind that both this and your example are copying the files in the current directory, so if you have more than one *.war, *.ejb or *.ear in your tree, only the last one(s) will be left in the target directory.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.