3

I need to rename a part of a Java JAR file and I need to keep the version numbers in the filename:

Original file: hello-service-0.1.0.jar
Expected file: hello-my-service-0.1.0.jar

The following command does the job properly, but I need to be in the directory where the file sits, so I need to change-directory before run the rename command:

cd "$dir"
rename --verbose "s/hello-service/hello-my-service/" *.jar
cd -

But as I run the rename from a bash script, I would like to avoid the boilerplate code that change directory before and after the rename command.

I have something like this:

dir="/home/me/projects/hello/jar"
actual="hello-service"
expected="hello-my-service"

rename --verbose "s/$actual/$expected/" *.jar

How to specify the directory name for the rename command?

0

2 Answers 2

5

Switch from s/.../.../ to s|...|...| to avoid escaping /:

rename --verbose 's|'"$actual"'([^/]*)$|'"$expected"'$1|' "$dir"/*.jar

[^/]*$: Make sure that there is no / after the name until the end of the file name.

$1: Back-reference to match of (...) to keep part after file name (in your example -0.1.0.jar).

5
  • 2
    That's much more complicated than the simpler (cd "$dir" && rename -v "s/hello-service/hello-my-service/" *.jar) (changing the directory in a subshell does not affect the current working directory of the calling shell). I really see no issue with using cd in this case, unless the rename utility has an option to only modify the filename portion of the given pathnames, as alluded to by steeldriver in comments. Commented Jul 12 at 8:45
  • 2
    @Kusalananda: I agree with you, but the questioner wanted to get rid of the directory change. Perhaps he didn't realize that the code wouldn't become any clearer or less complex as a result. Commented Jul 12 at 11:11
  • 2
    They want to get rid of their "boiler-plate code" that changes the directory before and after the call to rename. I agree that this I a good thing to want to get rid of. You don't usually want to see cd - in a script as it makes it difficult to follow. Commented Jul 12 at 11:12
  • 1
    Just a thought ... I don't know, but in case the OP is an XY problem then find's action -execdir might simplify things ... e.g. find /home/me/projects/hello/jar/ -type f -name '*.jar' -execdir rename -v "s/hello-service/hello-my-service/" {} + Commented Jul 12 at 17:06
  • Thanks for the comments, they helped a lot. For example, combining the commands that belong together with && makes scripts robust. Indeed, I expected cleaner code. I will use the accepted solution. Commented Jul 12 at 21:29
3

rename can take full pathnames as arguments. It also has a handy -d option so that it only renames the filename portion of a pathname, not the directory.

So, do this:

rename -v -d "s/$actual/$expected/" "$dir/"*.jar

Also, rename can take filenames to rename from stdin, and has a -0 option to tell it to use NUL as the filename separator, so you can also run something like this:

find "$dir" -type f -iname '*.jar' -print0 |
  rename -v -d -0 "s/$actual/$expected/"

See man rename for details on these and other options.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.