Search code examples
bashsedrenamecutxargs

Shorten filename to n characters while preserving file extension


I'm trying to shorten a filename while preserving the extension.

I think cut may be the best tool to use, but I'm not sure how to preserve the file extension.

For example, I'm trying to rename abcdefghijklmnop.txt to abcde.txt

I'd like to simply lop off the end of the filename so that the total character length doesn't exceed [in this example] 5 characters.

I'm not concerned with filename clashes because my dataset likely won't contain any, and anyway I'll do a find, analyze the files, and test before I rename anything.


The background for this is ultimately that I want to mass truncate filenames that exceed 135 characters so that I can rsync the files to an encrypted share on a Synology NAS.

I found a good way to search for all filenames that exceed 135 characters: find . -type f | awk -F'/' 'length($NF)>135{print $0}'

And I'd like to pipe that to a simple cut command to trim the filename down to size. Perhaps there is a better way than this. I found a method to shorten filenames while preserving extensions, but I need to recurse through all sub-directories.

Any help would be appreciated, thank you!

Update for clarification:

I'd like to use a one-liner with a syntax like this:

find . -type f | awk -F'/' 'length($NF)>135{print $0}' | some_code_here_to_shorten_the_filename_while_preserving_the_extension


Solution

  • With GNU find and bash:

    export n=10 # change according to your needs
    find . -type f                      \
         ! -name '.*'                   \
           -regextype egrep             \
         ! -regex '.*\.[^/.]{'"$n"',}'  \
           -regex '.*[^/]{'$((n+1))',}' \
           -execdir bash -c '
        echo "PWD=$PWD"
        for f in "${@#./}"; do
            ext=${f#"${f%.*}"}
            echo mv -- "$f" "${f:0:n-${#ext}}${ext}"
        done' bash {} +
    

    This will perform a dry-run, that is it shows folders followed by the commands to be executed within them. Once you're happy with its output you can drop echo before mv (and echo "PWD=$PWD" line too if you want) and it'll actually rename all the files whose names exceed n characters to names exactly of n characters length including extension.

    Note that this excludes hidden files, and files whose extensions are equal to or longer than n in length (e.g. .hidden, app.properties where n=10).