Linux rename files extension

Change extension of file using shell script

How to change extension of all *.dat files in a directory to *.txt. Shell script should take the directory name as an argument. Can take multiple directories as arguments. Print the log of command result in appending mode with date and timestamp.

10 Answers 10

Bash can do all of the heavy lifting such as extracting the extension and tagging on a new one. For example:

for file in $1/*.dat ; do mv "$file" "$.txt" ; done 

Welcome to Stack Overflow! While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.

# change .htm files to .html for file in *.htm ; do mv $file `echo $file | sed 's/\(.*\.\)htm/\1html/'` ; done # change .html files to .htm for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1htm/'` ; done #change .html files to .shtml for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1shtml/'` ; done #change .html files to php for file in *.html ; do mv $file `echo $file | sed 's/\(.*\.\)html/\1php/'` ; done 
# change .dat files to .txt for file in *.dat ; do mv $file `echo $file | sed 's/\(.*\.\)dat /\1txt/'` ; done 

@Kaz The $ is from bash and I can’t use bash. Pben’s answer is more cross-compatible which is often what I need.

@SebastianGodelet There is no difference between $ and $ when PAT is matches something of fixed length, like the literal text .dat . If your is just .html , it will not match all.html.files.tar.gz regardless of % versus %% .

#!/bin/bash for d in $*; do for f in $(ls $d/*.dat); do echo $(date) $(mv -v $f $.txt) done done 

Output redirection should be done by the shell when running the script

Leaving out argument validity checks

#!/bin/bash if [ $# -lt 2 ] then echo "Usage `basename $0` " exit 85 # exit status for wrong number of arguments. fi for directories do for files in $(ls $directories/*.dat); do echo $(date) $(mv -v $files $.txt) done done 

The first for loop by default loops on the $@ i.e. command-line arguments passed.

Follow Pben’s solution, if your filename contains blank space, you should use double quotation marks to the variable like the following:

#remove the space in file name #example file name:19-014-0100.mp3 .mp3 #result file name:19-014-0100.mp3 $ for file in *.mp3 ; do target=`echo "$file" | sed 's/ //g'`; echo "$target"; mv "$file" "$target"; done; #remove the duplicate file extension in file name #example file name:19-014-0100.mp3.mp3 #result file name:19-014-0100.mp3 $ for file in *.mp3 ; do target=`echo "$file" | sed 's/\.mp3\.mp3$/.mp3/g'`; echo "$target"; mv "$file" "$target"; done; 

To rename (changing extention) all my html files on epub files I use this command line :

find . -name "*.html*" -exec rename -v 's/\.html$/\.epub/i' <> \; 

rename command renames the filenames supplied according to the rule specified as the first argument. To install the rename command in ubuntu, run sudo apt install rename .

Читайте также:  Read linux usb on windows

Script, first finds the names of the given extensions. It removes the extension from names. Then adds backslash() for identification of terminal.

Then the ‘mv’ command executed. Here the ‘.temp’ folder is used to hide the process from user, in GUI.

#!/bin/sh if [ $# -ne 3 ] then echo "Usage: ./script folder current_extension modify_extension" exit fi mkdir .temp find $1 -name "*.$2" > .temp/output_1 && sed "s/$2//" .temp/output_1 > .temp/output_2 && sed -e "s/[ \t]/\\\ /g" .temp/output_2 > .temp/output_3 while read line do mv -v "$line""$2" "$line""$3" done < .temp/output_3 rm -rf .temp 

The output files are saved inside the '.temp' folder,later the '.temp' folder is removed.

Источник

Recursively rename files (change extension) in Linux

How do I rename all files in a directory, recursively, changing one file extension to another, for thousands of files in thousands of subfolders? I see a lot of commands that do almost what I want, but not quite.

find . -name "*.andnav" -exec rename .andnav .tile <> \; syntax error at (eval 1) line 1, near "." 
rename -nv 's/\.andnav$/\.tile/i' *.andnav 0.png.andnav renamed as 0.png.tile 

7 Answers 7

find . -name "*.andnav" -exec rename -v 's/\.andnav$/\.tile/i' <> \; ./0/0.png.andnav renamed as ./0/0.png.tile ./0/1.png.andnav renamed as ./0/1.png.tile ./1/0.png.andnav renamed as ./1/0.png.tile ./1/1.png.andnav renamed as ./1/1.png.tile 

of course remove the -v when actually doing it, or it will waste time displaying all the files

autoload zmv zmv -n '(**/)(*).andnav' '$1$2.tile' 

Remove the -n to actually perform the renaming.

find . -name '*.andnav' -exec sh -c 'mv "$0" "$.tile"' <> \; 

Explanation

The above starts walking the directory tree starting at the current working directory ( . ). Every time a file name matches the pattern *.andnav (e.g., foo.andnav ) the following command is executed:

Where $0 is foo.andnav and $.tile replaces the .andnav suffix with .tile so basically:

I just meant an explanation of the syntax and behaviour- people (like me!) might not be familiar with bash parameter expansion

I found this method is easier and easier to read:

find . -name "*.andnav" | rename "s/\.andnav$/.tile/" 

At least on Ubuntu derivations rename takes a list of files from STDIN if none are on the command line. And this can be tested easily with:

find . -name "*.andnav" | rename -vn "s/\.andnav$/.tile/" 

find -execdir rename

Читайте также:  Kali linux the quieter you

https://superuser.com/a/213146/128124 works directly only for suffixes, but this will work for arbitrary regex replacements on basenames:

PATH=/usr/bin find . -depth -execdir rename 's/_dbg.txt$/_.txt' '<>' \; 
PATH=/usr/bin find . -type f -execdir rename 's/_dbg.txt$/_.txt' '<>' \; 

-execdir first cd s into the directory before executing only on the basename.

Tested on Ubuntu 20.04, find 4.7.0, rename 1.10.

Convenient and safer helper for it

find-rename-regex() ( set -eu find_and_replace="$1" PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \ find . -depth -execdir rename "$" "s/$" '<>' \; ) 

Sample usage to replace spaces ' ' with hyphens '-'.

Dry run that shows what would be renamed to what without actually doing it:

Command explanation

The awesome -execdir option does a cd into the directory before executing the rename command, unlike -exec .

-depth ensure that the renaming happens first on children, and then on parents, to prevent potential problems with missing parent directories.

-execdir is required because rename does not play well with non-basename input paths, e.g. the following fails:

rename 's/findme/replaceme/g' acc/acc 

The PATH hacking is required because -execdir has one very annoying drawback: find is extremely opinionated and refuses to do anything with -execdir if you have any relative paths in your PATH environment variable, e.g. ./node_modules/.bin , failing with:

find: The relative path ‘./node_modules/.bin’ is included in the PATH environment variable, which is insecure in combination with the -execdir action of find. Please remove that entry from $PATH

-execdir is a GNU find extension to POSIX. rename is Perl based and comes from the rename package.

Rename lookahead workaround

If your input paths don't come from find , or if you've had enough of the relative path annoyance, we can use some Perl lookahead to safely rename directories as in:

git ls-files | sort -r | xargs rename 's/findme(. *\/)\/?$/replaceme/g' '<>' 

I haven't found a convenient analogue for -execdir with xargs : Xargs: change working directory to file path before executing?

The sort -r is required to ensure that files come after their respective directories, since longer paths come after shorter ones with the same prefix.

Источник

Recursively change file extensions in Bash

I want to recursively iterate through a directory and change the extension of all files of a certain extension, say .t1 to .t2 . What is the bash command for doing this?

@AmalAntony : If you don't have rename , write a shell script, which renames a single file (trivial to do in your simple case), and then use find to apply this script to all files with the offending extension.

6 Answers 6

find . -name "*.t1" -exec bash -c 'mv "$1" "$".t2' - '<>' + 

If you have rename available then use one of these:

find . -name '*.t1' -exec rename .t1 .t2 <> + 
find . -name "*.t1" -exec rename 's/\.t1$/.t2/' '<>' + 

(My version of rename doesn't allow the sed style substitution expression. Gotta love Linux. I used to have to install TotalCommander for Windows to do stuff like this.)

Читайте также:  Linux add ssh users

In case anyone is wondering what the "$<1%.t1>".t2 part does, like I did: It uses bash string manipulation to do the following: 1/ Take the first positional parameter $1 and truncate the .t1 string literal from its end (percentage sign % operator). 2/ Append the .t2 string literal to the result.

Delimiter argument should be ; instead of + if renaming all at once is required like this find . -name "*.t1" -exec bash -c 'mv "$1" "$<1%.t1>".t2' - '<>' \; . Otherwise with the + only one file will be renamed at a time. Ref

None of the suggested solutions worked for me on a fresh install of debian 11. This should work on any Posix/MacOS

find ./ -depth -name "*.t1" -exec sh -c 'mv "$1" "$.t2"' _ <> \; 

This is the only one worked for me. None of the accepted answer methods worked. I am on Ubuntu so probably a Debian/CentOs whatever thing. cheers

If your version of bash supports the globstar option (version 4 or later):

shopt -s globstar for f in **/*.t1; do mv "$f" "$.t2" done 

I would do this way in bash :

for i in $(ls *.t1); do mv "$i" "$.t2" done 

EDIT : my mistake : it's not recursive, here is my way for recursive changing filename :

for i in $(find `pwd` -name "*.t1"); do mv "$i" "$.t2" done 

Don't parse ls, and see the same page for why your find syntax is bad. Also, make sure you quote your variables

Or you can simply install the mmv command and do:

Here #1 is the first glob part i.e. the * in *.t1 .

Or in pure bash stuff, a simple way would be:

for f in *.t1; do mv "$f" "$.t2" done 

(i.e.: for can list files without the help of an external command such as ls or find )

I assume the OP's use of "recursively" refers to renaming files in subdirectories of the directory as well.

My lazy copy-pasting of one of these solutions didn't work, but I already had fd-find installed, so I used that:

fd --extension t1 --exec mv <> .t2 

From fd 's manpage, when executing a command (using --exec ):

 The following placeholders are substituted by a path derived from the current search result: <> path basename parent directory <.>path without file extension basename without file extension 

Источник

Оцените статью
Adblock
detector