How to remove characters from file names using command line?

51,479

Solution 1

You can achieve this with a for loop and some bash expansion. If you're already in the directory containing the files:

for f in ./*; do mv "$f" "${f%.*.gif}.gif" ; done

If your directory containing the files is called /home/gifstore/ :

for f in /home/gifstore/*; do mv "$f" "${f%.*.gif}.gif" ; done

The ${f...} performs expansion of each filename we've saved into the variable named f. The % in the expansion of the filename means remove the shortest match of the following pattern from the end of the variable. The pattern is .*.gif, meaning any amount of characters between . and .gif. Finally we append the literal string .gif outside of the expansion to create our new filename, and rely on the mv command to move the file.

This won't work for hidden files, starting with ..

Solution 2

The rename command (you can also run it as file-rename) is well-suited to this task. There are a few ways to use it here. I suggest this, though I'll show an alternative below:

rename -n 's/^\d{8}_\d\d\K\.\d+//' *.gif

The -n option makes it just print out what rename operations would be one first. Once you're happy with that, run it again without -n to do the actual renaming. One of the benefits of rename is that it will not overwrite files (unless you pass it the -f option, which you should very rarely do). That's especially good here because you're removing parts from filenames that potentially could result in naming collisions. Even if the collisions aren't detected when you perform the simulation with -n, they will be caught when you perform the actual renaming.

With the four files you showed, that command will show this output:

rename(22771786_01.204.gif, 22771786_01.gif)
rename(22771786_02.203.gif, 22771786_02.gif)
rename(22771786_03.10.gif, 22771786_03.gif)
rename(22771786_04.56.gif, 22771786_04.gif)

Of course, your output will be longer if you have more than four files, which I presume you do.


The way that command works is that s/ performs substitution. Filenames that contain text that matches the regular expression ^\d{8}_\d\d\K\.\d+ are changed so that the match is erased, i.e., replaced with the empty string which is between / and / in the // that follows it.

Although the regular expression could be written in such a way as to ensure that only files ending in .gif are operated on, this is unnecessary, because you can pass just the .gif filenames to rename. The shell expands *.gif to a list of those files and passes that list to the rename command. Note that the syntax the shell uses for filename expansion is not the same thing as regular expressions. * does not have the same meaning as in regular expressions.

Here's what the regular expression ^\d{8}_\d\d\K\.\d+ does:

  • ^ anchors to the beginning of the line.
  • \d{8} matches a sequence of exactly eight digits.
  • _ matches a literal _. It is not special.
  • \d\d matches two more digits.
  • \K forgets the preceding matched characters. These are the characters we want to keep, after all, not the ones we want to replace. The effect is to ensure those characters are present just before the part we will actually replace.
  • \. matches a literal .. The backslash is necessary because when a dot appears in a regular expression it otherwise matches any single character.
  • \d+ matches one or more digits.

Thus, it is a . followed by digits that get removed. If the file does not begin with the necessary pattern, then there is no match. This helps avoid renaming files you don't want to rename.

It's possible to write a shorter rename command that ought to work. I've chosen this approach--among many possible approaches--because the command expresses precisely the naming scheme that you wish to operate on. This is to say that the solution resembles the problem.


If you want to use a simpler rename command, and you know all the .gif files in the current directory are named according to your description and need to be renamed, you can use:

rename -n 's/\.\d+\.gif$/\.gif/' *

Remember that -n just shows you what will be done, and you must then remove it to actually rename files.

In that command, I've included the .gif suffix in the regular expression so you don't have to filter for it in the filenames you pass to rename. Still, you might choose to do so, if you have many non-.gif files in the current directory that would be pointlessly matched by *.

Here's what the regular expression \.\d+\.gif$ does:

  • \. matches a literal .. (Without the \, a . matches any character.)
  • \d+ matches one or more digits.
  • \. matches another literal ..
  • gif matches the literal text gif.
  • $ anchors the match to the end of the filename.

So the dot, the final digits, and the suffix .gif are matched, and all replaced with just .gif.

Solution 3

I personally enjoy using ranger for these type of things. It uses Vim keybindings for navigation and such, so if you're not familiar with vim it could get confusing/difficult. But if you're already familiar with Vim it should be a simple task!

Step 1

Install ranger. You can install it as a Vim plugin or just download the .tar.gz file from the website.

Step 2

Run Ranger and navigate to the directory that has the files you wish to rename. I would recommend putting all the .gifs in one directory. Make sure there are no other files except the ones you want to rename.

Step 3

Press v to select all files

Step 4

type :bulkrename and press Enter

Step 5

Use a Vim macro to record the changes you wish to make. So for your example, if you started on the very first line of the file you would use these commands:

q a (this starts the macro named "a")

0, f., de (moves cursor to start of the line, finds the first ".", then deletes to the last character before the second "." before gif)

q (to stop recording the macro)

Step 6

Move to the second line and move the cursor to the beginning of the line (j,0) and type :2,$norm! @a

This will run the macro you just made (named "a") from the second line all the way until the end of the file.

Step 7

:wq to save and exit and then :wq again to confirm the changes.


So if all goes well you should have renamed all of your files. If you haven't used Vim before, I would recommend using another answer so you don't have to learn Vim just to rename files. I prefer using Vim so this is my method of choice when bulk renaming.

Solution 4

rename 's/\..*\./\./' *.gif

It basically says "replace everything between characters . and . with just a single ."

Share:
51,479
a.v
Author by

a.v

Updated on September 18, 2022

Comments

  • a.v
    a.v over 1 year

    I have a bunch of files needing renaming but I do not want to create a script for it, just a command line.

    I need to remove the last digits between the . and the .gif:

    22771786_01.204.gif  
    22771786_02.203.gif  
    22771786_03.10.gif  
    22771786_04.56.gif
    

    To be like this:

    22771786_01.gif  
    22771786_02.gif  
    22771786_03.gif  
    22771786_04.gif
    
  • a.v
    a.v over 6 years
    It works so well!! :D Very simple and fantastic explanation! Thank you!!
  • a.v
    a.v over 6 years
    Very cool and simple as well! I liked both solutions presented and added to my library of useful commands. Thank you! :D
  • damadam
    damadam over 4 years
    Next time, add command line / terminal output as text instead of picture, it's easier for OP (and others readers) to use and test
  • Kokizzu
    Kokizzu almost 4 years
    -v for verbose, -f for force rename (overwrite)