If you have all of these files in one folder and you're on Linux you can use:
rename 's/test-this/REPLACESTRING/g' *
The result will be:
REPLACESTRING.ext
REPLACESTRING.volume001+02.ext
REPLACESTRING.volume002+04.ext
...
rename can take a command as the first argument. The command here consists of four parts:
s: flag to substitute a string with another string,test-this: the string you want to replace,REPLACESTRING: the string you want to replace the search string with, andg: a flag indicating that all matches of the search string shall be replaced, i.e. if the filename istest-this-abc-test-this.extthe result will beREPLACESTRING-abc-REPLACESTRING.ext.
Refer to man sed for a detailed description of the flags.
If you have all of these files in one folder and you're on Linux you can use:
rename 's/test-this/REPLACESTRING/g' *
The result will be:
REPLACESTRING.ext
REPLACESTRING.volume001+02.ext
REPLACESTRING.volume002+04.ext
...
rename can take a command as the first argument. The command here consists of four parts:
s: flag to substitute a string with another string,test-this: the string you want to replace,REPLACESTRING: the string you want to replace the search string with, andg: a flag indicating that all matches of the search string shall be replaced, i.e. if the filename istest-this-abc-test-this.extthe result will beREPLACESTRING-abc-REPLACESTRING.ext.
Refer to man sed for a detailed description of the flags.
Use rename as shown below:
rename test-this foo test-this*
This will replace test-this with foo in the file names.
If you don't have rename use a for loop as shown below:
for i in test-this*
do
mv "
{i/test-this/foo}"
done
You were right to consider rename first. The syntax is a little strange if you're not used to regexes but it's by far the quickest/shortest route once you know what you're doing:
rename 's/\d{4}/2503/' file*
That simply matches the first 4 numbers and swaps them for the ones you specified.
And a test harness (-vn means be verbose but don't do anything) using your filenames:
$ rename 's/\d{4}/2503/' file* -vn
file0901201437404.p renamed as file2503201437404.p
file0901201438761.p renamed as file2503201438761.p
file1003201410069.p renamed as file2503201410069.p
file2602201409853.p renamed as file2503201409853.p
file2602201410180.p renamed as file2503201410180.p
This should do the trick:
for f in file*; do mv
{f/${f:4:8}/25032014}; done
It replaces the string beween the 4th and the 12th character with "25032014".
How to bulk rename multiple files?
[BASH] Rename Multiple Files
How to rename multiple files with sed?
Easiest way to batch rename files
Videos
When thinking about writing this as a script I checked if possible names are already taken, and turns out my guess "interactive move" is already written and ready to use. For most systems it should be available in the renameutils-package, which contains various tools which are very helpful:
- qmv/qcp: Quick Move/Copy, writes all filenames to a text file which then can be edited.
- imv/icp: Interactive Move/Copy, asks for the new name of the files.
The problem with imv/icp in this case is, that those only accept one argument:
imv FILENAME
Multiple arguments will yield an error. So you'll basically have to wrap it up in a short for loop:
for file in *; do imv "$file"; done
That is of course hard to type, so we should wrap this into a ready to use function which we can place in our .bashrc file.
# Mass Interactive Move
function mimv {
for file in "
file"
done
}
Fortunately, imv shows the name of the file which is currently process, so we don't need any echo statement in there so that we know what is going on.
You can use this command:
for i in *; do
read -p "$i -> " newname
if [[ ! -z "$newname" ]]; then
mv -v -- "
newname"
fi
done
It will prompt you for a new name for every file and also for every directory (for i in *) in the current directory. The new name gets read into $newname. If you hit Enter without typing in a new name, nothing is done (-z $newname checks, if $newnameis empty (zero); ! is logical not), otherwise mv is used to rename the file.
If you want to change the file name only a little bit, it's more efficient if you can edit it, starting with the old file name, as suggested by @grawity:
for i in *; do
read -p "
i" newname
if [[ ! -z "$newname" ]]; then
mv -v -- "
newname"
fi
done
I tested it with filenames containing spaces and braces, however please use it on your own risk (and make a backup of the original files before).
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?
A simple for loop with a bit of sed will do the trick:
% touch xxxxx{foo,bar,baz}
% ls -l xxxxx{foo,bar,baz}
-rw-r--r-- 1 jamesog wheel 0 29 Dec 18:07 xxxxxbar
-rw-r--r-- 1 jamesog wheel 0 29 Dec 18:07 xxxxxbaz
-rw-r--r-- 1 jamesog wheel 0 29 Dec 18:07 xxxxxfoo
% for file in xxxxx*; do mv $file $(echo $file | sed -e 's/^.....//'); done
% ls -l foo bar baz
-rw-r--r-- 1 jamesog wheel 0 29 Dec 18:07 bar
-rw-r--r-- 1 jamesog wheel 0 29 Dec 18:07 baz
-rw-r--r-- 1 jamesog wheel 0 29 Dec 18:07 foo
The substitute regex in sed says to match any five characters (. means any character) at the start of the string (^) and remove it.
Bash has some amazing scripting possibilities. Here's one way:
for file in ??????*; do mv $file `echo $file | cut -c6-`; done
A handy way to test what it would do is to add an echo in front of the command:
for file in ??????*; do echo mv $file `echo $file | cut -c6-`; done
The six question marks ensure that you only attempt to do this to filenames longer than 5 characters.
Renaming files using mmv:
$ mmv '???-*' '#4'
^^^ ^ ^
123 4 4
You could also match digits with range match:
$ mmv '[0-9][0-9][0-9]-*.txt' '#4.txt'
^ ^ ^ ^ ^
1 2 3 4 4
(recursively rename files):
$ mmv ';???-*' '#1#5'
^^^^ ^ ^ ^
1234 5 1 5
;Expands to any number of directories (same as**/).*Matches any char zero or more times.?Matches any single character.[]Matches a list or and a range of characters.#References to the nth wildcard char in the from pattern.
With Perl-based rename command:
$ rename -n 's/\d{3}-//' [0-9][0-9][0-9]-*.txt
rename(000-hello.txt, hello.txt)
rename(001-world.txt, world.txt)
rename(002-ubuntu.txt, ubuntu.txt)
rename(003-linux.txt, linux.txt)
If the number of files is large enough to make the command exceed the shell's ARG_MAX, then you could use either
printf '%s\0' [0-9][0-9][0-9]-*.txt | xargs -0 rename -n 's/\d{3}-//'
or
find . -maxdepth 1 -name '[0-9][0-9][0-9]-*.txt' -exec rename -n 's/\d{3}-//' {} +
Note that [0-9][0-9][0-9]-*.txt is processed by the shell and needs to be a shell glob expression rather than a regular expression.
Remove the -n once you are happy that it is doing the right thing.
If you want to process files only in the top level of the directories (ie: one level deep), then you don't need recursion.
Both of these examples take a list of directories as arguments and rename only the files in those directories which match the more exclusive pattern: *-*.png (to avoid possible failures of the mv command).
A script that does NOT change directory:
In this first script, inside the for loop, the variable name contains the directory path to the file in addition to the base filename.
#!/bin/sh
for dir in "$@"
do
for name in "$dir"/*-*.png
do
mv "$name" "${name%-*}.png"
done
done
A script that DOES change directory:
In this second script, inside the for loop, the name variable contains only the filename, because the current directory has been temporarily changed to the script argument.
The code between the parenthesis ( and ), is executed in a subshell environment which means that changing the current directory, as well as variables set, will not be visible to the outer shell script, eliminating the need to change "back" to the original directory.
#!/bin/sh
for dir in "$@"
do
(
if cd "$dir"
then
for name in ./*-*.png
do
mv "$name" "${name%-*}.png"
done
fi
)
done
Notes About These Two Scripts:
The "$@" expands to the script's command line arguments. The script will silently do nothing with no arguments.
The directory-name arguments can be any absolute path (/path/to/dirx) or relative path (dirx, path/to/diry, ., .., ../x/d1, etc).
Messages will be printed on the standard error stream (stderr) by either mv or cd if a given directory does not exist, or if there are no *-*.png files in a directory. The script will continue processing subsequent directories.
The first line of these scripts can be #!/bin/sh instead of bash because this script uses none of the bash features, thus the more portable, posix compliant, and probably faster, sh can be used. Few scripts require the extra features of the bash shell. For these and other reasons #!/bin/bash is not generally recommended for scripting.
This worked for me
for dir in *; do if cd $dir; then for filename in *; do mv $filename "$filename.pdf"; done; cd ..; fi; done
prename
Simplest way would be to use rename or prename, which is a Perl script ( if you're a ksh or mksh user, that shell has rename built-in function, which is different, so for the sake of consistency, I'll use prename when referring to that Perl script; alternatively you could call /usr/bin/rename - full path to the executable).
$ ls
Session 1/ Session 2/ Session 3/ Session 4/ Session 5/ Session 6/ Session 7/ Session 8/
$ prename 's/Session/Folder/' Session*/
$ ls
Folder 1/ Folder 2/ Folder 3/ Folder 4/ Folder 5/ Folder 6/ Folder 7/ Folder 8/
If you need recursive search or ensure that you find the right type of item ( maybe you also have files with word "Session" in the filename) you can combine that with find utility:
$ ls
Folder 1/ Folder 2/ Folder 3/ Folder 4/ Folder 5/ Folder 6/ Folder 7/ Folder 8/
$ find -maxdepth 1 -type d -name "Session *" -exec prename 's/Session/Folder/' {} \;
$ ls
Folder 1/ Folder 2/ Folder 3/ Folder 4/ Folder 5/ Folder 6/ Folder 7/ Folder 8/
Slightly lengthy, maybe slightly redundant, but works.
mv
The small problem with mv is that we need to alter the name of the destination each time, so by itself it can't do what we want. To do that, we'd have to combine it with some other tools, such as find or bash's tools.
$ ls
Session 1/ Session 2/ Session 3/ Session 4/ Session 5/ Session 6/ Session 7/ Session 8/
$ for dir in Session*/ ; do mv "${dir}" "Folder ${dir##*\ }" ;done
$ ls
Folder 1/ Folder 2/ Folder 3/ Folder 4/ Folder 5/ Folder 6/ Folder 7/ Folder 8/
What you see here is that we're looping over all items that contain the word Session in them and are directory. We use parameter expansion `${dir##*\ }" to extract everything after space in directory's name ( which is the respective number), and form new string "Folder /".
In both prename commands and mv we're using globbing, which means these approaches will rename every directory that contains the word "Session" in them, even "Session blah". Not ideal, of course, but for the specific case where you know your folder naming is consistent, that'll work. Alternatively, we could augment the command with for dir in Session\ [1-9] ; do . . .done.
In other words,this approach can work, but is very simplistic and isn't the best.
Python
Of course, other tools can be used as well. For instance, Python:
$ ls
Session 1/ Session 3/ Session 5/ Session 7/
Session 2/ Session 4/ Session 6/ Session 8/
$ python -c 'import os,shutil;map(lambda x:shutil.move(x,x.replace("Session","Folder")),os.listdir("."))'
$ ls
Folder 1/ Folder 2/ Folder 3/ Folder 4/ Folder 5/ Folder 6/ Folder 7/ Folder 8/
Go to the folder that contens all the folder you want to rename and do:
find . * | rename 's\Session\Folder\'