1

I have some files such as:

20150716_something-here
20150716_something-heretoo
20150716_something-hereaswell

They need to be renamed as

2015-07-16_something-here
2015-07-16_something-heretoo
2015-07-16_something-hereaswell

I tried using a perl implementation of the rename command (see my comment on the accepted answer) but I was not successful.

1

Using the perl rename command (which is completely different to the rename command from util-linux):

rename -v 's/^(\d{4})(\d{2})(\d{2})/$1-$2-$3/' 2015*

(use -n rather than -v for a dry-run to test the command first).

This perl version of rename may be called prename or file-rename on your system. It is far more capable and useful than the util-linux version of rename. If you don't have it installed, you should install it. If it isn't packaged for your distro, you can install from CPAN

BTW, you can tell if you already have it installed by running rename -V. If it produces output like this:

$ rename -V
Unknown option: V
Usage: rename [-v] [-n] [-f] perlexpr [filenames]

or this:

$ rename -V
/usr/bin/rename using File::Rename version 0.20

Then you have perl rename installed. The former indicates an old version (which AFAIK lives on only on pre-jessie debian installs, included as part of the perl package). The latter indicates the current version (now a separate package called rename).

  • wooops, I did not realize I was using a perl implementation of rename. Installed this package using homebrew via brew install rename, now doing brew info rename prompts "Perl-powered file rename script" – Adrien Be May 27 '16 at 7:24
  • you might also be interested in this other answer i wrote about perl rename: unix.stackexchange.com/a/283606/7696 – cas May 27 '16 at 7:32
2

With sed:

LC_ALL=C sed -e 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)/\1_\2_\3/' <file
  • 1
    How does this rename a file? – Wildcard May 20 '16 at 5:27
  • This one just format the text, it does not rename the file – cuonglm May 20 '16 at 5:34
2

While rename is a very powerful tool, I normally prefer the simplicity of the mmv (multiple move) utility:

mmv '????????_*' '#1#2#3#4-#5#6-#7#8_#9'

The ? in the search pattern stands for a single character, the * for an arbitrarily long sequence of characters. In the replacement pattern, every #<number> stands for a corresponding ? or * in the search pattern. In addition to ? and *, mmv supports character ranges within brackets (like [a-f]).

(mmv will test for any conflicts in renaming before it starts work, so you do not risk losing files by overwriting.)

2

Using bash's built-in substring expansion:

for f in 2015* ; do
  mv "$f" "${f::4}-${f:4:2}-${f:6}"
done
0

On my distribution I have the perl-rename command, which can use a perl-style regex to bulk-rename files. The rename command only accepts a pair of fixed strings for the rename.

0

quick and dirty not full solution

#!/usr/bin/env bash
str=$1
yyyy=$(echo "$str" | awk -F '_' '{print $1}' | awk '{print substr($0, 1, 4)}')
mm=$(echo "$str" | awk -F '_' '{print $1}' | awk '{print substr($0, 5, 2)}')
dd=$(echo "$str" | awk -F '_' '{print $1}' | awk '{print substr($0, 7, 2)}')
new_str=$yyyy-$mm-$dd'_'`echo $str | awk -F'_' '{print $2}'`
echo $new_str

output:

$ bash script.sh '20150716_something-here'
2015-07-16_something-here

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.