I have many files with .abc
extension and want to change them to .edefg
How to do this from command line ?
I have a root folder with many sub-folders, so the solution should work recursively.
I have many files with .abc
extension and want to change them to .edefg
How to do this from command line ?
I have a root folder with many sub-folders, so the solution should work recursively.
A portable way (which will work on any POSIX compliant system):
In bash4, you can use globstar to get recursive globs (**):
The (perl)
rename
command in Ubuntu can rename files using perl regular expression syntax, which you can combine with globstar orfind
:Also see http://mywiki.wooledge.org/BashFAQ/030
This will do the required task if all the files are in the same folder
To rename the files recursively use this:
One problem with recursive renames is that whatever method you use to locate the files, it passes the whole path to
rename
, not just the file name. That makes it hard to do complex renames in nested folders.I use
find
's-execdir
action to solve this problem. If you use-execdir
instead of-exec
, the specified command is run from the subdirectory containing the matched file. So, instead of passing the whole path torename
, it only passes./filename
. That makes it much easier to write the regex.In detail:
-type f
means only look for files, not directories-name '*.abc'
means only match filenames that end in .abc'{}'
is the placeholder that marks the place where-execdir
will insert the found path. The single-quotes are required, to allow it to handle file names with spaces and shell characters.-type
and-name
are the bash line-continuation character. I use them to make this example more readable, but they are not needed if you put your command all on one line.-execdir
line is required. It is there to escape the semicolon, which terminates the command run by-execdir
. Fun!Explanation of the regex:
s/
start of the regex\.\/
match the leading ./ that -execdir passes in. Use \ to escape the . and / metacharacters (note: this part vary depending on your version offind
. See comment from user @apollo)(.+)
match the filename. The parentheses capture the match for later use\.abc
escape the dot, match the abc$
anchor the match at the end of the string/
marks the end of the "match" part of the regex, and the start of the "replace" partversion1_
add this text to every file name$1
references the existing filename, because we captured it with parentheses. If you use multiple sets of parentheses in the "match" part, you can refer to them here using $2, $3, etc..abc
the new file name will end in .abc. No need to escape the dot metacharacter here in the "replace" section/
end of the regexBefore
After
Hint:
rename
's -n option is useful. It does a dry run and shows you what names it will change, but does not make any changes.Another portable way:
Also see the entry on why you shouldn't parse
ls
.Edit: if you have to use basename your syntax would be:
https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files
I'd use the mmv command from the package of the same name:
The
;
matches zero or more*/
and corresponds to#1
in the replacement. The*
corresponds to#2
. The non-recursive version would beThis is what I did and worked pretty just the way I wanted. I used the
mv
command. I had multiple.3gp
files and I wanted to rename them all to.mp4
Here's a short oneliner for it:
Which simply scans through the current directory, picks up all .3gp files, then renames (using the mv) into
ren-name_of_file.mp4
I found an easy way to achieve this. To change extensions of many files from jpg to pdf, use:
Rename files and directories with
find -execdir | rename
If you are going to rename both files and directories not simply with a suffix, then this is a good pattern:
The awesome
-execdir
option does acd
into the directory before executing therename
command, unlike-exec
.-depth
ensure that the renaming happens first on children, and then on parents, to prevent potential problems with missing parent directories.-execdir
is required because rename does not play well with non-basename input paths, e.g. the following fails:The
PATH
hacking is required because-execdir
has one very annoying drawback:find
is extremely opinionated and refuses to do anything with-execdir
if you have any relative paths in yourPATH
environment variable, e.g../node_modules/.bin
, failing with:See also: Why using the '-execdir' action is insecure for directory which is in the PATH?
-execdir
is a GNU find extension to POSIX.rename
is Perl based and comes from therename
package. Tested in Ubuntu 18.10.Rename lookahead workaround
If your input paths don't come from
find
, or if you've had enough of the relative path annoyance, we can use some Perl lookahead to safely rename directories as in:I haven't found a convenient analogue for
-execdir
withxargs
: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686The
sort -r
is required to ensure that files come after their respective directories, since longer paths come after shorter ones with the same prefix.