Linux rename files by pattern

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

Hot Network Questions

Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.14.43533

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.

Источник

Rename files using regular expression in linux

what should I do to make the job done in linux terminal? I have installed rename but U get errors using the following:

rename -n 's/(\w+) - (\d)x(\d)*$/S0$2E$3\.srt/' *.srt 

10 Answers 10

You forgot a dot in front of the asterisk:

rename -n 's/(\w+) - (\d)x(\d).*$/S0$2E$3\.srt/' *.srt 

On OpenSUSE, RedHat, Gentoo you have to use Perl version of rename . This answer shows how to obtain it. On Arch, the package is called perl-rename .

Читайте также:  Alfa network awus036h kali linux

@mmrmartin: The rename script used here is the one written by Larry Wall. It used be in the file /usr/bin/rename , but perhaps it has been renamed (no pun intended)? On Debian the script name is now /usr/bin/file-rename .

openSUSE uses rename from util-linux package, I didn’t find any package providing file-rename , prename or perl-rename — only working solution was install using cpan for me.

@mmrmartin Same problem on RHEL 6, which also uses rename based on util-linux . See stackoverflow.com/a/48280659/1236128.

xargs -n2 makes it possible to print two arguments per line. When combined with Perl’s print $_ (to print the $STDIN first), it makes for a powerful renaming tool.

find . -type f | perl -pe 'print $_; s/input/output/' | xargs -d "\n" -n2 mv 

Results of perl -pe ‘print $_; s/OldName/NewName/’ | xargs -n2 end up being:

OldName1.ext NewName1.ext OldName2.ext NewName2.ext OldName3.ext NewName3.ext OldName4.ext NewName4.ext 

I did not have Perl’s rename readily available on my system.

  1. find . -type f outputs file paths (or file names. you control what gets processed by regex here!)
  2. -p prints file paths that were processed by regex, -e executes inline script
  3. print $_ prints the original file name first (independent of -p )
  4. -d «\n» cuts the input by newline, instead of default space character
  5. -n2 prints two elements per line
  6. mv gets the input of the previous line

My preferred approach, albeit more advanced.

Let’s say I want to rename all «.txt» files to be «.md» files:

find . -type f -printf '%P\0' | perl -0 -l0 -pe 'print $_; s/(.*)\.txt/$1\.md/' | xargs -0 -n 2 mv 

The magic here is that each process in the pipeline supports the null byte (0x00) that is used as a delimiter as opposed to spaces or newlines. The first aforementioned method uses newlines as separators. Note that I tried to easily support find . without using subprocesses. Be careful here (you might want to check your output of find before you run in through a regular expression match, or worse, a destructive command like mv ).

How it works (abridged to include only changes from above)

  1. In find : -printf ‘%P\0’ print only name of files without path followed by null byte. Adjust to your use case-whether matching filenames or entire paths.
  2. In perl and xargs : -0 stdin delimiter is the null byte (rather than space)
  3. In perl : -l0 stdout delimiter is the null byte (in octal 000)

The last command should be changed to xargs -d ‘\n’ -n2 mv , otherwise xargs will treat spaces in filenames as delimiters and either cause errors, or rename files nonsensically. The -d ‘\n’ argument specifies that newlines should be treated as the delimiter. GNU xargs has the -d argument, but for those implementations that do not (i.e. FreeBSD which I was using), this would work across most environments: find . -type f | perl -pe ‘print $_; s/input/output/’ | sed ‘s/ /\\ /g’ xargs -n2 mv by using sed to escape all spaces in the output that’s piped to xargs . (Not elegant, perhaps.)

Читайте также:  Shutdown linux kali linux

@s.co.tt A perhaps better way to treat spaces as normal chars is to use a different dilimiter char. Xargs supports the 0-byte and so does find. I‘d do a find -print0 followed by a xargs -0 .

Another improvement would be to pre-filter the results from the find through grep to minimize the no-op renames: find . -type f | grep ‘input’ | perl -pe ‘print $_; s/input/output/’ | xargs -n2 mv

Use mmv (mass-move?)

It’s simple but useful: The * wildcard matches any string (without / ) and ? matches any character in the string to be matched. In the replace string, use #N to refer to the N-th wildcard match.

mmv 'Friends - 6x?? - Tow *.srt' 'S06E#1#2.srt' 

Here, #1#2 represent the two digits which are captured by ?? (match #1 and #2).
So the following replacement is being made:

The pattern string: 'Friends - 6x?? - Tow * .srt' matches this file: Friends - 6x03 - Tow Ross' Denial.srt ↓↓ will be renamed to: S06E03.srt 

Personally, I use it to pad numbers such that numbered files appear in the desired order when sorted lexicographically (e.g., 1. appears before 10. ): file_?.ext → file_0#1.ext

mmv also offers matching by [ and ] and ; .

You can not only mass rename, but also mass move, copy, append and link files.

Edit: found a better way to list the files without using IFS and ls while still being sh compliant.

I would do a shell script for that:

#!/bin/sh for file in *.srt; do if [ -e "$file" ]; then newname=`echo "$file" | sed 's/^.*\(9\+\)x\(9\+\).*$/S0\1E\2.srt/'` mv "$file" "$newname" fi done 
#!/bin/sh IFS=' ' for file in `ls -1 *.srt`; do newname=`echo "$file" | sed 's/^.*\(9\+\)x\(2\+\).*$/S0\1E\2.srt/'` mv "$file" "$newname" done 

IFS: The Internal Field Separator that is used for word splitting after expansion and to split lines into words with the read builtin command. The default value is «» — (from man bash). Changing it to \n allows to get one file per line.

You could extend the script to support recursive action with: for file in `find . -type f`; do (But then you need to update the sed to capture the path also)

Not every distro ships a rename utility that supports regexes as used in the examples above — RedHat, Gentoo and their derivatives amongst others.

Alternatives to try to use are perl-rename and mmv .

if your linux does not offer rename, you could also use the following:

find . -type f -name "Friends*" -execdir bash -c 'mv "$1" "$"' _ <> \; 

i use this snippet quite often to perform substitutions with regex in my console.

Читайте также:  Install steam client on linux

i am not very good in shell-stuff, but as far as i understand this code, its explanation would be like: the search results of your find will be passed on to a bash-command (bash -c) where your search result will be inside of $1 as source file. the target that follows is the result of a substitution within a subshell, where the content of $1 (here: just 1 inside your parameter-substituion 1//find/replace>) will also be your search result. the <> passes it on to the content of -execdir

better explanations would be appreciated a lot 🙂

please note: i only copy-pasted your regex; please test it first with example files. depending on your system you might need to change \d and \w to character classes like [[:digit:]] or [[:alpha:]]. however, \1 should work for the groups.

Источник

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)

@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.

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.14.43533

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.

Источник

Оцените статью
Adblock
detector