- Better way to rename files based on multiple patterns
- 5 Answers 5
- Two answer: using perl rename or using pure bash
- Renaming files by using the rename command.
- Introduction
- More oriented samples
- Full syntax for matching SO question, in safe way
- Renaming files by using bash and so called bashisms:
- How to rename all files in folders with pattern
- 3 Answers 3
- You must log in to answer this question.
- Related
- Hot Network Questions
- Subscribe to RSS
- command to mass rename files according to pattern [closed]
- 4 Answers 4
- Linked
- Related
- Hot Network Questions
Better way to rename files based on multiple patterns
a lot of files I download have crap/spam in their filenames, e.g. [ www.crap.com ] file.name.ext www.crap.com — file.name.ext I’ve come up with two ways for dealing with them but they both seem pretty clunky: with parameter expansion:
if [[ $ != $ ]] then mv -v "$/$" "$/$" && base_name="$" fi if [[ $ != $ ]] then mv -v "$/$" "$/$" && base_name="$" fi # more of these type of statements; one for each type of frequently-encountered pattern
tmp=`echo "$" | sed -e 's/\[[^][]*\]//g' | sed -e 's/\s-\s//g'` mv "$" ""
I feel like the parameter expansion is the worse of the two but I like it because I’m able to keep the same variable assigned to the file for further processing after the rename (the above code is used in a script that’s called for each file after the file download is complete). So anyway I was hoping there’s a better/cleaner way to do the above that someone more knowledgeable than myself could show me, preferably in a way that would allow me to easily reassign the old/original variable to the new/renamed file. Thanks
create a temporary file with a ls, change it with a sed and apply result (ex: mv «/Path/www.crap.com — file.name.ext» «/Path/file.name.ext»)
5 Answers 5
Two answer: using perl rename or using pure bash
As there are some people who dislike perl, I wrote my bash only version
Renaming files by using the rename command.
Introduction
Yes, this is a typical job for rename command which was precisely designed for:
man rename | sed -ne '/example/,/^[^ ]/p' 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/' *
More oriented samples
Simply drop all spaces and square brackets:
Rename all .jpg by numbering from 1 :
rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg
touch .jpg ls -ltr total 0 -rw-r--r-- 1 user user 0 sep 6 16:35 e.jpg -rw-r--r-- 1 user user 0 sep 6 16:35 d.jpg -rw-r--r-- 1 user user 0 sep 6 16:35 c.jpg -rw-r--r-- 1 user user 0 sep 6 16:35 b.jpg -rw-r--r-- 1 user user 0 sep 6 16:35 a.jpg rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg ls -ltr total 0 -rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00005.JPG -rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00004.JPG -rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00003.JPG -rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00002.JPG -rw-r--r-- 1 user user 0 sep 6 16:35 IMG_00001.JPG
Full syntax for matching SO question, in safe way
There is a strong and safe way using rename utility:
As this is perl common tool, we have to use perl syntax:
rename 'my $o=$_; s/[ \[\]]+/-/g; s/-+/-/g; s/^-//g; s/-\(\..*\|\)$/$1/g; s/(.*[^\d])(|-(\d+))(\.[a-z0-9])$/ my $i=$3; $i=0 unless $i; sprintf("%s-%d%s", $1, $i+1, $4) /eg while $o ne $_ && -f $_; ' *
touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext' ls -1 [ www.crap.com ] file.name.ext www.crap.com - file.name.ext rename 'my $o=$_; . . . ' * ls -1 www.crap.com-file.name-1.ext www.crap.com-file.name.ext touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext' ls -1 www.crap.com-file.name-1.ext [ www.crap.com ] file.name.ext www.crap.com - file.name.ext www.crap.com-file.name.ext rename 'my $o=$_; . . . ' * ls -1 www.crap.com-file.name-1.ext www.crap.com-file.name-2.ext www.crap.com-file.name-3.ext www.crap.com-file.name.ext
. and it’s safe while you don’t use -f flag to rename command: file won’t be overwrited and you will get an error message if something goes wrong.
Renaming files by using bash and so called bashisms:
I prefer doing this by using dedicated utility, but this could even be done by using pure bash (aka without any fork)
There is no use of any other binary than bash (no sed , awk , tr or other):
#!/bin/bash for file;do newname=$ while [ "$newname" != "$" ] ;do newname=$ done while [ "$newname" != "$" ] ;do newname=$;done if [ "$file" != "$newname" ] ;then if [ -f $newname ] ;then ext=$ basename=$ partname=$ count=$-> [ "$partname" = "$count" ] && count=0 while printf -v newname "%s-%d.%s" $partname $[++count] $ext && [ -f "$newname" ] ;do :;done fi mv "$file" $newname fi done
To be run with files as argument, for sample:
- Replacing spaces and square bracket by dot
- Replacing sequences of .- , -. , — or .. by only one — .
- Test if filename don’t differ, there is nothing to do.
- Test if a file exist with newname.
- split filename, counter and extension, for making indexed newname
- loop if a file exist with newname
- Finaly rename the file.
Take advantage of the following classical pattern:
job_select /path/to/directory| job_strategy | job_process
where job_select is responsible for selecting the objects of your job, job_strategy prepares a processing plan for these objects and job_process eventually executes the plan.
This assumes that filenames do not contain a vertical bar | nor a newline character.
The job_select function
# job_select PATH # Produce the list of files to process job_select()
The find command can examine all properties of the file maintained by the file system, like creation time, access time, modification time. It is also possible to control how the filesystem is explored by telling find not to descend into mounted filesystems, how much recursions levels are allowed. It is common to append pipes to the find command to perform more complicated selections based on the filename.
Avoid the common pitfall of including the contents of hidden directories in the output of the job_select function. For instance, the directories CVS , .svn , .svk and .git are used by the corresponding source control management tools and it is almost always wrong to include their contents in the output of the job_select function. By inadvertently batch processing these files, one can easily make the affected working copy unusable.
The job_strategy function
# job_strategy # Prepare a plan for renaming files job_strategy() < sed -e ' h s@/www\..*\.com - *@/@ s@/\[^]]* - *@/@ x G s/\n/|/ ' >
This commands reads the output of job_select and makes a plan for our renaming job. The plan is represented by text lines having two fields separated by the character | , the first field being the old name of the file and the second being the new computed file of the file, it looks like
[ www.crap.com ] file.name.1.ext|file.name.1.ext www.crap.com - file.name.2.ext|file.name.2.ext
The particular program used to produce the plan is essentially irrelevant, but it is common to use sed as in the example; awk or perl for this. Let us walk through the sed -script used here:
h Replace the contents of the hold space with the contents of the pattern space. … Edit the contents of the pattern space. x Swap the contents of the pattern and hold spaces. G Append a newline character followed by the contents of the hold space to the pattern space. s/\n/|/ Replace the newline character in the pattern space by a vertical bar.
It can be easier to use several filters to prepare the plan. Another common case is the use of the stat command to add creation times to file names.
The job_process function
# job_process # Rename files according to a plan job_process()
The input field separator IFS is adjusted to let the function read the output of job_strategy . Declaring oldname and newname as local is useful in large programs but can be omitted in very simple scripts. The job_process function can be adjusted to avoid overwriting existing files and report the problematic items.
About data structures in shell programs Note the use of pipes to transfer data from one stage to the other: apprentices often rely on variables to represent such information but it turns out to be a clumsy choice. Instead, it is preferable to represent data as tabular files or as tabular data streams moving from one process to the other, in this form, data can be easily processed by powerful tools like sed , awk , join , paste and sort — only to cite the most common ones.
How to rename all files in folders with pattern
Is the number of sections always the same, or should we work with S0 something? And what is the distibguising marker: barbeque? mp4? (probably omg looking at your attempt).
3 Answers 3
rename -n 's/^bla\.super\.lol\.[sS](\d+)[eE](\d+)\..*(\.mp4$)/s$1e$2$3/' *.mp4
-n does the dry-running, if you are satisfied with the potential renaming, just remove -n to let the actual renamimg to take place:
rename 's/^bla\.super\.lol\.[sS](\d+)[eE](\d+)\..*(\.mp4$)/s$1e$2$3/' *.mp4
$ ls -1 bla.super.lol.S01E03.omg.bbq.mp4 bla.super.lol.S01E04.omg.bbq.mp4 bla.super.lol.s03e12.omg.bbq.mp4 $ rename -n 's/^bla\.super\.lol\.[sS](\d+)[eE](\d+)\..*(\.mp4$)/s$1e$2$3/' *.mp4 bla.super.lol.S01E03.omg.bbq.mp4 renamed as s01e03.mp4 bla.super.lol.S01E04.omg.bbq.mp4 renamed as s01e04.mp4 bla.super.lol.s03e12.omg.bbq.mp4 renamed as s03e12.mp4
You could also, if you know that s\d<2>e\d <2>will only show up once replace the bla\.super. with just [A-Za-z0-9.]+ or even .+ , since + is non-greedy. This would allow your answer to work for any input of the same pattern (garbage + s01e01 + garbage.mp4)2>
@Musher FIle renaming should not be based on any assumption..also your regex could be simplified to just [\w.] ..also + is Greedy..
#!/bin/bash IFS="\n" # Handle files with spaces in the names for file in *.mp4; do newfile="$" # Strip the prefix you don't want newfile="$" # Change the first S to an s newfile="$" # Change the first E to an e newfile="$" # Strip the suffix you don't want newfile="$.mp4>" # Tack on the file extension again done if [[ "$file" == "$newfile" ]]; then echo "Not renaming $file - no change decreed." elif [[ -f "$newfile" ]]; then echo "Not renaming $file - $newfile already exists." else mv -- "$file" "$newfile" # Make the change fi
$ echo 'bla.super.lol.S01E03.omg.bbq.mp4' | perl -pe 's/.*\.(\w+)\.omg\..*mp4$/\L$1.mp4/' s01e03.mp4
You must log in to answer this question.
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.17.43537
Ubuntu and the circle of friends logo are trade marks of Canonical Limited and are used under licence.
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.
command to mass rename files according to pattern [closed]
I have a lot of files in a directory that are named as follows ID_OTHER_STUFF.txt I’d like to rename them all to ID.txt. This isn’t a duplicate because I don’t know how to specify this pattern.
You can’t rename them all to the same name in the same directory — you would have to move them all to different directories.
4 Answers 4
Using the perl script prename , which is symlinked to rename on Debian based distros.
Remove the -n once you are sure it does what you want.
BTW obviously the ID part is a stand-in for the number. Rather than putting them in different directories according to ID, could we put them all in one directory, but the files just named ID? This answer is very good thank you.
Becareful w/ the rename command there’s the Perl script version (Debian/Ubuntu) and an actual executable (Red Hat distros). unix.stackexchange.com/questions/24761/….
You want to use your shell’s parameter expansion to manipulate the name, like this:
for file in *.txt do mv $file $.txt done
$ ls -1 1_foo_bar.txt 2_foo_bar.txt $ for file in *.txt for> do for> mv $file $.txt for> done $ ls -1 1.txt 2.txt
Look up Parameter Expansion in your shell’s man page for more details about $ usage.
1_other_stuff.txt 2_other_stuff.txt 3_other_stuff.txt
$ seq 1 3 | xargs -I ID mv ID_other_stuff.txt ID.txt
Wont work, mv only takes more that 2 arguments when the last one is a directory. Then it puts the files in that directory. Using mv requires one run per file. You can do this in a loop or use rename which is the standard tool for doing this kind of thing.
You want to mv them in a loop, mini bash script, there are several variations. in this Question Batch renaming files.
I’m looking for a line of code that turns that particular pattern into the other specified pattern, thanks.
all of the answers in that post can be written on one line, and contain the fundamental principles behind both of the other two answers, given to your question here.
Linked
Related
Hot Network Questions
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.17.43537
Linux is a registered trademark of Linus Torvalds. UNIX is a registered trademark of The Open Group.
This site is not affiliated with Linus Torvalds or The Open Group in any way.
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.