1

On a Linux server I have a directory full of files with digits for names. Some of the files start with two zeros such as 00305005. I am writing a bash shell script and one of the steps is to rename all of the files that start with 00 so they start with @0. The file I mentioned earlier would be @0305005.

The issue I am having is that when I try to rename the files I end up changing all instances of 00 in the file name to @0 like this: @0305@05. I have been using the following code and I don't know how to fix it:

for f in 00*; do mv "$f" "${f//00/@0}"; done

DavevaD
  • 23
  • 6
  • Please take a look at: [What should I do when someone answers my question?](http://serverfault.com/help/someone-answers) – Cyrus Jul 14 '19 at 07:41

2 Answers2

1

If you're stuck with shell magic then go a different path and try transforming the file name with a different tool, such as f.ex. sed

for f in 00*; do
  new_f=$( echo "$f" | sed 's/00/@0/' )
  echo mv "$f" "$f_new"
done

I've inserted the echo before the mv so that you can test first if the mvs look OK, before you wreck your files. You can then remove that echo.

1

When you use ${var//pattern/replacement}, the // means "replace all occurrences". In this case you only want to replace the first occurrence, so you can use just /. Or, you could be even more specific, and use /#, which will replace only at the beginning of the string; this shouldn't make a difference since you're only processing files that start with 00, but I'd be inclined to use it to make the goal explicit. Here's a demo:

$ f=00305005
$ echo "${f//00/@0}"    # // = replace all
@0305@05
$ echo "${f/00/@0}"     # /  = replace first one -- this does what you want
@0305005
$ echo "${f/#00/@0}"    # /# = replace at beginning -- this also does what you want
@0305005
$ g=90305005            # Let's test with a name that *doesn't* start with 00
$ echo "${g/00/@0}"     # / replaces the first match, no matter where it is in the string
90305@05
$ echo "${g/#00/@0}"    # /# does not replace if the beginning does not match
90305005

I'd also recommend using mv -i for any sort of bulk move/rename, to avoid data loss if there's a naming conflict or error. Thus, here's what I'd recommend:

for f in 00*; do mv -i "$f" "${f/#00/@0}"; done
Gordon Davisson
  • 11,216
  • 4
  • 28
  • 33