Search code examples
bashfor-looprenamemv

Renaming files with multiple variables in the file names


I have multiple files with this format: this-is-text_r_123.txt and this-is-text.txt.

What I would like to do (preferable using a for loop) is to rename all this-is-text.txt files to their corresponding this-is-text_r_123.txt matches but have an i instead of the r in the file name. Considering that this-is-text is a random text (different from one file to another) and the 123 in the example above is any combination of 3 numbers. All files are in one directory.

I tried with mv and rename but I wasn't successful

I've searched and reviewed all the file renaming questions here but none matched my case


Solution

  • I changed the technology to Python to demonstrate how to do this in a language more convenient than bash:

    #!/usr/bin/python3
    import glob
    import re
    
    text_files = glob.glob('*.txt')
    
    #divide the files into two groups: "normal" files without _r and "target" files with _r
    normal_files = {}
    target_files = {}
    for path in text_files:
        #extract "key" (meaning part of file name without _r or _i)
        #as well as whether the file contains _r or _i, or not
        #using regular expressions:
        result = re.match('(?P<key>.*?)(?P<target>_[ri]_?\d*)?\..*$', path)
        if result:
            if result.group('target'):
                target_files[result.group('key')] = path
            else:
                normal_files[result.group('key')] = path
    
    print(normal_files)
    print(target_files)
    
    #now figure out how to rename the files using the built dictionaries:
    for key, path in normal_files.items():
        if key in target_files:
            target_path = target_files[key].replace('_r', '_i')
            print('Renaming %s to %s' % (path, target_path))
    

    For following set of files:

    asd.txt
    asd_r_1.txt
    test test.txt
    test test_r2.txt
    another test_i_1.txt
    

    this script will produce:

    {'test test': 'test test.txt', 'asd': 'asd.txt'}
    {'test test': 'test test_r2.txt', 'another test': 'another test_i_1.txt', 'asd': 'asd_r_1.txt'}
    Renaming test test.txt to test test_i2.txt
    Renaming asd.txt to asd_i_1.txt
    

    You should be able to move files with this.

    As you see, it works.

    If you really need doing this in bash, it should be easy to port using sed or awk.