Linux: remove file extensions for multiple files

LinuxBashRename

Linux Problem Overview


I have many files with .txt extension. How to remove .txt extension for multiple files in linux?

I found that

rename .old .new *.old

substitutes .old extension to the .new

Also I want to do this for files in sub-folders.

Linux Solutions


Solution 1 - Linux

rename is slightly dangerous, since according to its manual page:

> rename will rename the specified files by replacing the first occurrence of...

It will happily do the wrong thing with filenames like c.txt.parser.y.

Here's a solution using find and bash:

find -type f -name '*.txt' | while read f; do mv "$f" "${f%.txt}"; done

Keep in mind that this will break if a filename contains a newline (rare, but not impossible).

If you have GNU find, this is a more solid solution:

find -type f -name '*.txt' -print0 | while read -d $'\0' f; do mv "$f" "${f%.txt}"; done

Solution 2 - Linux

I use this:

find ./ -name "*.old" -exec sh -c 'mv $0 `basename "$0" .old`.new' '{}' \;

Solution 3 - Linux

The Perl version of rename can remove an extension as follows:

rename 's/\.txt$//' *.txt

This could be combined with find in order to also do sub-folders.

Solution 4 - Linux

You can explicitly pass in an empty string as an argument.

rename .old '' *.old

And with subfolders, find . -type d -exec rename .old '' {}/*.old \;. {} is the substitute for the entry found with find, and \; terminates the arglist for the command given after -exec.

Solution 5 - Linux

In case it helps, here's how I do it with zsh:

for f in ./**/*.old; do
    mv "${f}" "${f%.old}"
done

The ${x%pattern} construct in zsh removes the shortest occurence of pattern at the end of $x. Here it is abstracted as a function:

function chgext () {
    local srcext=".old"
    local dstext=""
    local dir="."

    [[ "$#" -ge 1 ]] && srcext="$1"
    [[ "$#" -gt 2 ]] && dstext="$2" dir="$3" || dir="${2:-.}"

    local bname=''
    for f in "${dir}"/**/*"${srcext}"; do
        bname="${f%${srcext}}"
        echo "${bname}{${srcext}${dstext}}"
        mv "${f}" "${bname}${dstext}"
    done
}

Usage:

chgext
chgext src
chgext src dir
chgext src dst dir

Where `src` is the extension to find (default: ".old")
      `dst` is the extension to replace with (default: "")
      `dir` is the directory to act on (default: ".")

Solution 6 - Linux

In Fish, you can do

for file in *.old
      touch (basename "$file" .old).new
end

Solution 7 - Linux

For subfolders:

for i in `find myfolder -type d`; do
  rename .old .new $i/*.old
done

Solution 8 - Linux

execute in bash linux

for i in *;do mv ${i} ${i/%.pdf/} ;done

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionrp101View Question on Stackoverflow
Solution 1 - LinuxthkalaView Answer on Stackoverflow
Solution 2 - LinuxChris CowanView Answer on Stackoverflow
Solution 3 - LinuxAndrew SView Answer on Stackoverflow
Solution 4 - LinuxrobertView Answer on Stackoverflow
Solution 5 - LinuxsvvacView Answer on Stackoverflow
Solution 6 - LinuxBruno AlanoView Answer on Stackoverflow
Solution 7 - LinuxKonrad GarusView Answer on Stackoverflow
Solution 8 - Linuxshahin arefView Answer on Stackoverflow