How to bulk rename files using wildcards?

I have a lot of files with a naming scheme like

[String] [Int-Int] String Int [String] [String].format

And I need to be able to rename them to

[String] String Int [String].format

So for example I have a file named

[Abc] [58-97] bcde 05 [123a] [A2BCF3].txt

And I need it renamed to

[Abc] bcde 05 [123a].txt

But it’s not just one file, I have hundreds of files with the same kind of name pattern that I also need to rename in the exact same way.

How can I achieve this?

I mean ideally I’d want to just be able to do something like rename -v 's/[*-*]//' *.txt as a start, then figure out something for that last string in a separate command. But clearly that command won’t work or I wouldn’t be here asking for help :slight_smile:

If there are spaces and/or other special characters in the filenames, then you need to quote your variables. Try something like this… :arrow_down:

rename -v 's/[*-*]//' "*.txt"

It just returns:

rename: not enough arguments
Try 'rename --help' for more information.

Also, just to be clear, using rename is not a requirement, I can use another program if there’s one that can do it more easily.

If you’re using The Superior Desktop™, KRename supports regular expressions and previews before committing to the bulk rename. You can add individual files or entire folders (even recursively) in your batch job.

It also comes with some nifty plugins too. But in your case, the “Find and Replace” option (under the Filename tab) should suffice.


Make sure not to hit Finish until everything in the preview pane looks correct.

3 Likes

Well, I have never used rename, but it either way doesn’t appear to be working the way you intended it. I’m looking at the man page now, and it doesn’t appear to support regular expressions.

I would probably tackle something like that with a script, involving either sed or tr. :thinking:

Ah, the regular expressions supported in krename conflict with my patterns

[ ] is read as regex character set by krename.

so [*-*] doesn’t give the result I want :confused:

Not sure how to fix that…

Escape the brackets with a backslash.

Tried this, but it didn’t seem to work.

I tried a bunch of things but it’s just not behaving like I expect.

\[*-*\]

and

[*-*]

Give the same result, it removes the very first [String] and the second [String] (should only remove the [Int-Int]) keeping the [Int-Int] and the last [String] (the exact two things I want to remove :grimacing: )

][*].txt

and

\]\[*\].mkv

Which should remove only the last [String] but it instead achieves the exact same result as the above. I am very confused rn.

The asterisks don’t work the same in regex.

You can use regex101.com with the string

[Abc] bcde 05 [123a].txt

To try and find “hits”.


EDIT: I just read your initial post; forgot what you were trying to “remove”. Oh boy, any regex wizards in here that know the expression to change,

[Abc] [58-97] bcde 05 [123a] [A2BCF3].txt

To this…

[Abc] bcde 05 [123a].txt

2 Likes

Ugh I give up, I’ve been messing with that regex101.com for a while now and I just can’t find anything that works D:

The closet thing I could muster ends up deleting every “brackets group”, leaving you with:

bcde 05.txt

:cold_sweat:

Here, try this:

(?: \[\d*-\d*\])|(?: \[[[:xdigit:]]{6}\])

I’m assuming the last “bracket group” is a consistent 6-character HEX string, while the second “bracket group” is always two numbers with a hyphen between.

In KRename, you would “replace” these with “nothing”, which essentially removes them.


EDIT: Nope, still nada. But I think I’m getting closer…

I managed to get rid of the [int-int] which is the most important part but it was messy af

I tried that last one you suggested but it wouldn’t work. (neither part)

Either way now I only need to lose the last one, the one you assumed is probably a cinsistent 6-character HEX string (you are probably right about this)

yeah I decided I don’t need to get rid of that last bracket with the hexadecimal numbers in it, it can stay, I mainly needed to get rid of the [int-int] string because it was ■■■■■■■ up my file sorting :stuck_out_tongue:

Thank you for your help man :slight_smile:

I think I have just found a way ─ in fact, one that could have done the whole job ─ to get rid of it.

So, if I understand you correctly, then you now have files in the format… ↓

[Abc] bcde 05 [123a] [A2BCF3].txt

… and they would need to be… ↓

[Abc] bcde 05 [123a].txt

…, is that correct?

That is correct, yes

Edit: actually it’d be [Abc] bcde 05 [123a][A2BCF34E].txt

I made a mistake in the OP with the spacing and with the total number of characters in that last bracket.

Okay, then let’s try this ─ untested, though… :arrow_down:

#!/bin/bash

for filename in *
do
      old=$(basename "${filename%.*}")
      suffix=$(basename "${filename##old}")
      new=$(echo "${old}" | awk 'END { print $1" "$2" "$3" "$4 }')
      echo Rename "${old}${suffix}" to "${new}${suffix}"? [Y/n]
      read -p reply
      if [ "$reply" == "Y" -o "$reply" == "y" ]
      then
         mv "${old}${suffix}" "${new}${suffix}"
      fi
done

There’s a built-in safety ─ it asks for confirmation ─ but still… :arrow_down:

:crossed_fingers:

  • It is of course a bash script, so you should save it in ~/.local/bin and give it execute permission before attempting to run it.

  • If it works on the first couple of files, then you can interrupt the script with Ctrl+C, edit the script, remove the confirmation check, save it and then run it again.

2 Likes

Beat me to it :wink:
I also wasnt sure if its all in the same directory or if we need to recursively find them…
So heres a quick version for that, though it only checks for the first 2 columns.
(could be expanded, could be fed to a rename action, or could just be tested to see if it finds everything)

find ./ -type f -name '\[[A-Z][a-z][a-z]\]\ \[[0-9][0-9]\-[0-9][0-9]\]'*
1 Like

Looks like a CRC32 checksum. I would leave them in the file’s name, since it’s a free pre-hashed value.

I was going to mention it earlier, but then I saw it was only 6 hexadecimal digits; but now you’ve made an update and it is indeed 8 hexadecimal digits.

1 Like

Your script returns this:

awk: cmd. line:1: END { print $1" "$2" "$3" "$4
awk: cmd. line:1:                              ^ unexpected newline or end of string

Thank you for your effort though, but you really don’t need to worry about it :smiley: I’m already satisfied with just having removed the [Int-Int] part, that was my main goal. Removing the (what I now presume to be) CRC32 Checksum part was just an afterthought really, it’s not necessary, it would just be for aesthetics anyways.

1 Like