2

I have a set of files whose names contain the character *. For Example, a file name could be ***abcdef. I want to change this file name to 3_abcdef, replacing the * with the number of * that were there.

I have a script to rename multiple files, but I don't know how to change that script to do the above task.

This is wjat I have so far:

find drp/ -depth -name "*abc.tab" -exec rename 's/\abc.tab$/xyz.tab/' {} +

How can I adapt it to this task?

  • DoI understand correctly that you want to name it after the number of * -es? – Jacob Vlijm Oct 31 '14 at 8:11
  • Is the number of asterisks related to the number you're sticking on the front? – Oli Oct 31 '14 at 8:25
7

You can use an actual expression with rename. In this case we match as many asterisks as there are, and then replace that with the length of the match:

rename 's/^[*]+/sprintf("%d_", length $&)/e' -vn *

If that looks right, remove the -n argument. That's just there to allow you to test it safely.

Here's my test harness:

$ touch \*{,\*{,\*}}abc.tab
$ rename 's/^[*]+/sprintf("%d_", length $&)/e' -vn *
***abc.tab renamed as 3_abc.tab
**abc.tab renamed as 2_abc.tab
*abc.tab renamed as 1_abc.tab

If you also want to do another rename, you can chain it in:

$ rename 's/^[*]+/sprintf("%d_", length $&)/e; s/abc/xyz/' -vn *
***abc.tab renamed as 3_xyz.tab
**abc.tab renamed as 2_xyz.tab
*abc.tab renamed as 1_xyz.tab
  • I tried your scripts. After executing the script, I got the message in terminal screen as every file has renamed. But When I want to look at the files, It doesn't change the file names. – Smith Dwayne Oct 31 '14 at 11:37
  • 5
    Sorry, remove the -n argument. That's in there for safety-testing. – Oli Oct 31 '14 at 11:45
1

Assuming you'd like to replace the number of preceding "*" by the actual number (like in your example), and taking into account the possibility of the existance of sub folders and ignoring invisible files, a python option would be:

#!/usr/bin/env python3

import os
import shutil
import sys

sourcedir = sys.argv[1]

for root, dirs, files in os.walk(sourcedir):
    for name in files:
        if not name.startswith(".") and name.count("*") != 0:
            number = name.count("*"); newname = str(number)+"_"+name.replace("*", "")
            shutil.move(root+"/"+name, root+"/"+newname)

Copy it into an empty file, save it as rename.py, run it by the command:

python3 path/to/rename.py </path/to/files>

it renames

****banana.txt
**monkey.mp3
**************test

into:

4_banana.txt
2_monkey.mp3
14_test
1

Incase if you need a one liner bash script.

$ find . -type f -exec bash -c 'file=$(basename "$0"); rn=$(echo "$file"|grep -o "*"|wc -l); on=$(echo "$file"|tr -d "*"); mv "$file" "${rn}_${on}"' {} \;

$ ls 
0_a.txt  1_a.txt  2_a.txt  3_a.txt

And if you need a shell script.

#!/bin/bash

changed=0

for file in *
do
    rn=$(echo "$file"|grep -o '*'| wc -l)
    on=$(echo "$file"|tr -d '*')
    if [ "$rn" -ne 0 ]
    then
        mv -v "$file" "$rn"_"$on"
        ((changed++))
    fi
done

if [ $changed -gt 0 ]
then
    echo "Have renamed $changed files"
else
    echo "There are no files to rename"
fi

Output

$ ./a.sh 
`***a.txt' -> `3_a.txt'
`**a.txt' -> `2_a.txt'
`******b.txt' -> `6_b.txt'
`**b.txt' -> `2_b.txt'
Have renamed 4 files

I would recommend to use shell script as it has more validations.

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.