9

I've got some files like this:

database1-backup-01-01-2011.sql
database2-backup-01-01-2011.sql

...etc. I want to rename them to add AM, like this:

database1-backup-01-01-2011-AM.sql
database2-backup-01-01-2011-AM.sql

What's the most concise way to do that from the bash shell?

5 Answers 5

22

Another option:

for i in *.sql ; do
    mv -v $i ${i%.sql}-AM.sql
done

This loops through all the .sql files and renames them to end in -AM.sql instead.

PROTIP: Use $(command) instead of `command` in your scripts (and command-lines), it makes quoting and escaping less of a nightmare.

2
  • Nice - the most concise way so far. Mar 2, 2011 at 14:50
  • The suggested edit is not an "attempt" to reply, but rather an extension of the original answer. It adds an explanation to the answer and not a reply.
    – zx485
    Jul 2, 2020 at 2:14
8

Try this little script:

#!/bin/sh

FILES=`ls *.sql`
for FILE in ${FILES}
{
    BASE=`basename ${FILE} .sql`
    mv ${FILE} ${BASE}-AM.sql
}

I just typed that from memory so if it doesn't work 100% don't blame me (i.e., back up your data first ;) )

How it works:

Collect all files into a variable (you could put this inside the for instead but I like to keep things easy to read):

FILES=`ls *.sql`

Loop through each file:

for FILE in ${FILES} { ... }

Get the filename without .sql:

BASE=`basename ${FILE} .sql`

Rename the file, adding -AM.sql to the base name:

mv ${FILE} ${BASE}-AM.sql
9
  • 3
    You can remove the line FILES=`ls *.sql` and replace ${FILES} by *.sql, shell expansion will take care of finding the files.
    – Lekensteyn
    Mar 2, 2011 at 14:48
  • This isn't the most concise way, but I do appreciate the readability and explanation. If I'm going to do this from the command line, I'd rather type what chrish shows, but if I were saving it as a script, I'd definitely use your way for readability. Mar 2, 2011 at 14:51
  • 1
    @Matt Jenkins: the readability does not increase by adding another ls command. Keep it simple. By the way, I think the { are bashish, it's better to replace them by do and done: for ...; do ...; done
    – Lekensteyn
    Mar 2, 2011 at 14:53
  • 1
    @Matt Jenkins: FILES=`ls *.sql` <-- there. Shell expansion is built-in, no need for this extra ls.
    – Lekensteyn
    Mar 2, 2011 at 14:56
  • 2
    Well forgive me for writing portable code. ls.. is just one source of files that the script could handle; it would be trivial to change it to use, say, a predefined list of files, or command line arguements, by just editing this variable. No need to change the structure of the for if you want to put the script to another use. Isn't that the point of this site? To give answers that are of interest to the genral populace? If that means making your scripts a little more wordy and a little more understandable then I don't see a problem with ls.. as it implicitly shows what is being worked on.
    – Majenko
    Mar 2, 2011 at 15:01
6

Using the Perl script version of rename:

rename 's/\.sql$/-AM$&/' *.sql

Using the util-linux-ng version of rename (but only if ".sql" only appears at the end of the filename):

rename .sql -AM.sql *.sql

Using mmv:

mmv '*.sql' '#1-AM.sql'
2

Since a Perl script has been suggested, here's a Ruby script to do the same:

`ls *.sql`.split("\n").each do |filename|
  new_filename = filename.split('.').join('-AM.')
  `mv #{filename} #{new_filename}`
end
1
  • Wow, I never noticed how the Ruby back-ticks make this look like such a seamless integration with shell.
    – vincent
    Feb 22 at 19:08
0

I suggest to use qmv from renameutils

The qmv program will open list of filenames of choosen directory in your default text editor and allows you to edit them. When you save this edited file list, it applies new names to actual files.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.