I have a file named 35554842200284685106000166550020003504201637715423.xml and I simply need to rename it to 42200284685106000166550020003504201637715423.xml (remove everything before the last 48 characters). This simple regular expression (.{48}$) can extract the last 48 characters, but I can't make it work using rename in Bash.

How can I use rename and this regular expression to rename it to only the last 48 characters?


Output of rename --help

[root@ip-000-00-0-000 tmp]# rename --help

 rename [options] <expression> <replacement> <file>...

Rename files.

 -v, --verbose    explain what is being done
 -s, --symlink    act on the target of symlinks
 -n, --no-act     do not make any changes

 -h, --help     display this help and exit
 -V, --version  output version information and exit

For more details see rename(1).

Thank you.

  • 8
    Can you show us what you've tried, please. It also depends on the version of rename you're using - if you type rename just by itself what error message does it give you? – roaima Feb 24 at 12:35
  • 2
    For example, rename 's/^.*(.{44}\.xml$)/$1/' 3*.xml works perfectly here – roaima Feb 24 at 12:39
  • 4
    renames are legion. In different distros they may be differently... named. :) – Kamil Maciorowski Feb 24 at 12:43
  • I'm executing these commands on an AWS EC2 (Amazon Linux AMI) and executing the example sent by @roaima outputs a 'not enough arguments' error. Also, typing rename by itself also outputs 'not enough arguments'. – devegili Feb 24 at 12:52
  • 5
    Yep, that's the util-linux rename, you are looking for perl-rename or prename. By the way, please don't post images of text. Instead, paste the text directly into your question and use the formatting tools to format it as code. – terdon Feb 24 at 13:06

You don't actually need rename here, you can work around it:

$ file=35554842200284685106000166550020003504201637715423.xml
$ newname=$(sed -E 's/.*(.{48})/\1/'<<<"$file"); 
$ mv -v "$file" "$newname"
renamed '35554842200284685106000166550020003504201637715423.xml' -> '42200284685106000166550020003504201637715423.xml'
|improve this answer|||||

Here is one using bash specific P.E. parameter expansion.


Only mv for external tools

mv -v "$file" "${file:6}"


renamed '35554842200284685106000166550020003504201637715423.xml' -> '42200284685106000166550020003504201637715423.xml'

Keeping the last 48 chars would be.

mv -v "$file" "${file:(-48)}"
|improve this answer|||||
  • 1
    On my phone so can't test, but would ${file#??????} be a posix sh compatible alternative? – kojiro Feb 25 at 12:00
  • @kojiro It is, tested on dash ash, ksh,zsh – Jetchisel Feb 25 at 12:12
  • mksh,pdksh. it does not work however on *csh shell variants and fish. The thing is the OP wants to retain the last 48 chars. – Jetchisel Feb 25 at 12:21

Your rename seems to be the useless one from util-linux.

You'd want to make sure one of the perl-based variants is installed instead (sometimes called prename) if you want to use regular expressions. And then:

rename -n 's:^\./\d+(?=\d{44}\.xml\Z)::' ./*.xml

(here replacing your 48 characters, with 44 digits followed by .xml so as to be more specific).

Alternatively, you could use zsh's zmv:

autoload zmv
zmv -n '[0-9]##([0-9](#c44).xml)' '$1'


zmv -n '<->.xml~^?(#c48)' '$f[-48,-1]'

(remove -n (dry-run) to actually do it).

Which also has the benefit of guarding against conflicts (two files having the same destination name)

With bash, you could do something like:

shopt -s extglob nullglob
for f in +([[:digit:]]).xml; do
  ((${#f) <= 48)) || echo mv -i -- "$f" "${f: -48}"
|improve this answer|||||
  • I've also seen it called perl-rename and rename-perl – Mutantoe Feb 25 at 12:31
rename  "s/"$file"/"${file: -48}"/" *.xml

rename --version:

/usr/bin/rename using File::Rename version 1.10
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.