There are several ways, but using rename will probably be the easiest.
Using one version of rename (Perl's rename):
rename 's/^fgh/jkl/' fgh*
Using another version of rename (same as Judy2K's answer):
rename fgh jkl fgh*
You should check your platform's man page to see which of the above applies.
Answer from Stephan202 on Stack OverflowThere are several ways, but using rename will probably be the easiest.
Using one version of rename (Perl's rename):
rename 's/^fgh/jkl/' fgh*
Using another version of rename (same as Judy2K's answer):
rename fgh jkl fgh*
You should check your platform's man page to see which of the above applies.
This is how sed and mv can be used together to do rename:
for f in fgh*; do mv "
(echo "$f" | sed 's/^fgh/jkl/g'); done
As per comment below, if the file names have spaces in them, quotes may need to surround the sub-function that returns the name to move the files to:
for f in fgh*; do mv "
(echo $f | sed 's/^fgh/jkl/g')"; done
Rename multiple files by replacing a particular pattern in the filenames using a shell script - Stack Overflow
How to bulk rename multiple files?
Rename multiple files with mv to change the extension - Unix & Linux Stack Exchange
How to rename multiple files by removing the extension? - Unix & Linux Stack Exchange
Videos
I use rename all the time. It is pretty simple, but hopefully you know basic regex:
rename "s/SEARCH/REPLACE/g" *
This will replace the string SEARCH with REPLACE in every file (that is, *). The /g means global, so if you had a SEARCH_SEARCH.jpg, it would be renamed REPLACE_REPLACE.jpg. If you didn't have /g, it would have only done substitution once, and thus now named REPLACE_SEARCH.jpg. If you want case-insensitive, add /i (that would be, /gi or /ig at the end).
With regular expressions, you can do lots more.
Note that this rename is the prename (aka Perl rename) command, which supports complete Perl regular expressions. There is another rename which uses patterns, and is not as powerful. prename used to be installed by default on Ubuntu (along with Perl), but now you may have to do:
sudo apt install rename
Here are a few examples:
Prefix
Add:
rename 's/^/MyPrefix_/' *
document.pdfrenamed toMyPrefix_document.pdf
Remove:
Also you can remove unwanted strings. Let's say you had 20 MP3 files named like CD RIP 01 Song.mp3 and you wanted to remove the "CD RIP" part, and you wanted to remove that from all of them with one command.
rename 's/^CD RIP //' *
CD RIP 01 Song.mp3to01 Song.mp3
Notice the extra space in '^CD RIP ', without the space all files would have a space as the first character of the file. Also note, this will work without the ^ character, but would match CD RIP in any part of the filename. The ^ guarantees it only removes the characters if they are the beginning of the file.
Suffix
Add:
rename 's/$/_MySuffix/' *
document.pdfrenamed todocument.pdf_MySuffix
Change:
rename 's/\.pdf$/.doc/' *
will change Something.pdf into Something.doc. (The reason for the backslash is, . is a wildcard character in regexp so .pdf matches qPDF whereas \.pdf only matches the exact string .pdf. Also very important to note, if you are not familiar with BASH, you must put backslashes in SINGLE quotes! You may not omit quotes or use double quotes, or bash will try to translate them. To bash \. and "\." equals .. (But double-quotes and backslashes are used, for example "\n" for a newline, but since "\." isn't a valid back escape sequence, it translates into .)
Actually, you can even enclose the parts of the string in quotes instead of the whole: 's/Search/Replace/g' is the same as s/'Search'/'Replace'/g and s/Search/Replace/g to BASH. You just have to be careful about special characters (and spaces).
I suggest using the -n option when you are not positive you have the correct regular expressions. It shows what would be renamed, then exits without doing it. For example:
rename -n s/'One'/'Two'/g *
This will list all changes it would have made, had you not put the -n flag there. If it looks good, press Up to go back, then erase the -n and press Enter (or replace it with -v to output all changes it makes).
Note: Ubuntu versions above 17.04 don't ship with rename by default, however it's still available in the repositories. Use sudo apt install rename to install it
Try pyrenamer.
It's not integrated with nautilus, but it gets the job done. Here is a review.
Thunar (part of XFCE) also has a renamer that you can run separately.

An example to help you get off the ground.
for f in *.jpg; do mv "$f" "$(echo "$f" | sed s/IMG/VACATION/)"; done
In this example, I am assuming that all your image files contain the string IMG and you want to replace IMG with VACATION.
The shell automatically evaluates *.jpg to all the matching files.
The second argument of mv (the new name of the file) is the output of the sed command that replaces IMG with VACATION.
If your filenames include whitespace pay careful attention to the "$f" notation. You need the double-quotes to preserve the whitespace.
You can use rename utility to rename multiple files by a pattern. For example following command will prepend string MyVacation2011_ to all the files with jpg extension.
rename 's/^/MyVacation2011_/g' *.jpg
or
rename <pattern> <replacement> <file-list>
I have an offline playlist full of .mp3's. But the issue is most of them have [SPOTIFY-DOWNLOADER] in the beginning of their names. How do I remove it?
I know this doesn't answer your question, but in case you were looking for another way to rename the files compared to your work-around loop, why not use find? I have used this command many times to replace file extensions in large directories with hundreds of thousands of files in it. This should work on any POSIX-compliant system:
find . -name "*.gappedPeak" -exec sh -c 'mv "
{1%.gappedPeak}.bed"' _ {} \;
Command Breakdown:
'
.' => search path starting at current directory marked by ' . '
-name=> set find match name (in this case all files that end with.gappedPeak)
-exec=> execute the following command on every match
sh -c=> 'exec' creates an independent shell environment for each match
mv "=>{1%.gappedPeak}.bed"
mvfirst variable (denoted by $1), which is the current file name, to new name. Here I do a substring match and delete; so take first var again, $1 and use%to delete.gappedPeakfrom the string. The.bedat the end just concatenates the remaining variable, which in the example below would now betestNumber, with.bed, creating the newtestNumber.bedfilename.The underscore is a placeholder for $0
The
{}is replaced by each (*.gappedPeak) filename found by thefindcommand, and becomes $1 to theshcommand.
\;marks the end of the-execcommand. You can also use';'or";".
Example:
[user@before]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.gappedPeak
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.gappedPeak
[user@after]# ls -lh
total 0
-rw-r--r--. 1 root root 0 Jan 26 11:40 test1.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test2.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test3.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test4.bed
-rw-r--r--. 1 root root 0 Jan 26 11:40 test5.bed
This answer won't help you change the extension, but it will help you understand why your command is not doing what you expect.
When you issue the command:
mv *.txt *.tsv
the shell, lets assume bash, expands the wildcards if there are any matching files (including directories). The list of files is passed to the program, here mv. If no matches are found the unexpanded version is passed.
Again: the shell expands the patterns, not the program.
Loads of examples is perhaps best way to understand why this won't work. So here we go:
Example 1:
$ ls
file1.txt file2.txt
$ mv *.txt *.tsv
Now what happens on the mv line is that the shell expands *.txt to the matching files. As there are no *.tsv files that is not changed.
The mv command is called with two special arguments:
argc: Number of arguments, including the program.argv: An array of arguments, including the program as first entry.
In the above example that would be:
argc = 4
argv[0] = mv
argv[1] = file1.txt
argv[2] = file2.txt
argv[3] = *.tsv
The mv program checks to see if the last argument, *.tsv, is a directory. As it is not, the program can not continue as it is not designed to concatenate files. (combine all the files into one.) Nor can it create directories on a whim.
As a result, it aborts and reports the error:
mv: target ‘*.tsv’ is not a directory
Example 2:
Now if you instead say:
$ mv *1.txt *.tsv
The mv command is executed with:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[2] = *.tsv
Now, again, mv checks to see if *.tsv exists. As it does not, the file file1.txt is moved to *.tsv. That is: the file is renamed to *.tsv with the asterisk and all.
$ mv *1.txt *.tsv
‘file1.txt’ -> ‘*.tsv’
$ ls
file2.txt *.tsv
Example 3:
If you instead said:
$ mkdir *.tsv
$ mv *.txt *.tsv
The mv command is executed with:
argc = 3
argv[0] = mv
argv[1] = file1.txt
argv[1] = file2.txt
argv[2] = *.tsv
As *.tsv now is a directory, the files end up being moved there.
Now: using commands like some_command *.tsv when the intention is to actually keep the wildcard one should always quote it. By quoting you prevent the wildcards from being expanded if there should be any matches. E.g. say mkdir "*.tsv".
Example 4:
The expansion can further be viewed if you do, for example:
$ ls
file1.txt file2.txt
$ mkdir *.txt
mkdir: cannot create directory ‘file1.txt’: File exists
mkdir: cannot create directory ‘file2.txt’: File exists
Example 5:
Now: the mv command can and does work on multiple files. But if there are more than two the last one has to be a target directory. (Optionally you can use the -t TARGET_DIR option, at least for GNU mv.)
So this is OK:
mv *.txt *.tsv foo
Here mv would be called with:
argc = 7
argv[0] = mv
argv[1] = b1.tsv
argv[2] = b2.tsv
argv[3] = f1.txt
argv[4] = f2.txt
argv[5] = f3.txt
argv[6] = foo
and all the files end up in the directory foo.
As for your links. You have provided one (in a comment), where mv is not mentioned at all, but rename. Do you have more links or man pages that you could share where your claim is expressed?
perl's rename (as typically found on Debian where it's also called prename), or this derivative (rename package on Debian):
rename 's/\.tif$//' *.tif
util-linux rename (as typically found on Red Hat, rename.ul on Debian):
rename -- .tif '' *.tif
(note that that one would rename blah.tiffany.tif to blahfany.tif)
For a non-rename, you might do:
i `basename $i .tif`; done
(-i to warn against replacing a file)
rename 's/ACDC/AC-DC/' *.xxx
from man rename
DESCRIPTION
"rename" renames the filenames supplied according to the rule specified as the
first argument. The perlexpr argument is a Perl expression which is expected to modify the
$_ string in Perl for at least some of the filenames specified. If a given filename is not
modified by the expression, it will not be renamed. If no filenames are given on
the command line, filenames will be read via standard input.
For example, to rename all files matching "*.bak" to strip the extension, you might say
rename 's/\.bak$//' *.bak
To translate uppercase names to lower, you'd use
rename 'y/A-Z/a-z/' *
This answer contains the good parts from all other answers, while leaving out such heresy as ls | while read.
Current directory:
for file in ACDC*.xxx; do
mv "$file" "${file//ACDC/AC-DC}"
done
Including subdirectories:
find . -type f -name "ACDC*" -print0 | while read -r -d '' file; do
mv "$file" "${file//ACDC/AC-DC}"
done
Newline characters are really unlikely to be in filenames, so this can be simpler while still working with names containing spaces:
find . -type f -name "ACDC*" | while read -r file; do
mv "$file" "${file//ACDC/AC-DC}"
done
You can do this with the rename command line utility. To do what you want you need a simple regular expression:
rename "s/.+_/ds/g"files
.+ represents everything up to (in this context) the last underscore (_) character (so this works with multiple underscores, as mentioned in your first example). This requires that there be at least one character before the underscore; if you might have file names like _20131012.zip, use .* instead. So this three-character string (.+_ or .*_) will match everything up to and including the last underscore in the filename. s/old/new/ means substitute the new string (ds) for the old string. The g means global and might not be necessary in this case.
or, using the cross-platform renamer:
$ renamer --regex --find '.+_' --replace 'ds' *