23

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.

Mainak
  • 311
  • 2
  • 4
  • 7

10 Answers10

41

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" "${file%.*}.txt" ; done
Aki Korhonen
  • 511
  • 4
  • 4
  • 2
    Welcome to Stack Overflow! While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) 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. – Ferrybig Nov 18 '16 at 10:23
  • This is a bash solution while the OP asked for a shell solution. Does not work on POSIX environment. – Dunatotatos Jul 04 '17 at 13:43
21

Batch File Rename By File Extension in Unix

# 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

so ==>

# change .dat files to .txt
for file in *.dat ; do mv $file `echo $file | sed 's/\(.*\.\)dat /\1txt/'` ; done
Pben
  • 1,081
  • 7
  • 12
  • 22
    mv $file ${file%.dat}.txt # know thy shell builtin cruft – Kaz Mar 07 '12 at 03:01
  • why not `'s/\.htm$/\.html/'` – Sebastian Jul 10 '14 at 12:27
  • 2
    @Kaz, better use `${file%%}`, since one might have something like `all.html.files.tar.gz` – Sebastian Jul 10 '14 at 12:42
  • @Kaz The ${file %.dat} is from bash and I can't use bash. Pben's answer is more cross-compatible which is often what I need. – DKATyler Dec 24 '15 at 16:58
  • @user1361991 `${VAR%PATTERN}` is POSIX-standard shell syntax. – Kaz Dec 24 '15 at 17:56
  • 1
    @SebastianGodelet There is no difference between `${VAR%PAT}` and `${VAR%%PAT}` 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 `%%`. – Kaz Dec 24 '15 at 18:00
8
#!/bin/bash
for d in $*; do
    for f in $(ls $d/*.dat); do
        echo $(date) $(mv -v $f ${f%.dat}.txt)
    done
done

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

Leaving out argument validity checks

Alex
  • 10,470
  • 8
  • 40
  • 62
2

Simple script:

#!/bin/bash

if [ $# -lt 2 ] then
    echo "Usage `basename $0` <any number of directories space separated>"
    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 ${files%.dat}.txt)
    done
done

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

mtk
  • 13,221
  • 16
  • 72
  • 112
1

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;
Amitabha
  • 1,693
  • 2
  • 25
  • 42
1

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' {} \;
Tunaki
  • 132,869
  • 46
  • 340
  • 423
eugene
  • 11
  • 1
  • `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`. – t98907 Aug 23 '22 at 06:15
0

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.

0

The top voted answer didn't really work for me. I may have been doing something wrong. My scenario was trying to create a file with the original name, but with the date appended to it, along with changing the extension from .xslx to .csv. This is what worked for me:

csvname=`echo $xlsx |sed 's/\.xlsx//'`"-$now"`echo $xlsx | sed 's/\(.*\.\)xlsx/\.csv/'`

So, for all the .dat files in a directory (without the date addition), you could run something like this:

for i in *.dat
do mv $i `echo $i |sed 's/\.dat//'``echo $i | sed 's/\(.*\.\)dat/\.txt/'`
done

From the above, this section of code just removed the extension:

echo $i |sed 's/\.dat//'

And this section changes the .dat to .txt:

echo $i | sed 's/\(.*\.\)dat/\.txt/'

And by bumping them next to each other, it concatenates the two outputs into the filename. It's like doing this:

mv [filename][.dat] [filename] + [.txt]

Though, I did use STDOUT instead of the 'mv' command.

William Cates
  • 93
  • 1
  • 5
  • I encountered the same issue with the top-voted answer, however, the top-voted answer is more concise and provides enough detail for me to make it work. – DKATyler Dec 24 '15 at 16:53
0

Following command to change file extention .c to .h

find . -depth -name "*.c" -exec sh -c 'dname=$(dirname {}) && fname=$(basename {} .c) && mv {} $dname/$fname.h' ";"
vinoth kumar
  • 183
  • 1
  • 1
  • 8
0

change js to cjs extension files recursively:

cd dist # where you place your .js
for file in $(find . -type f -name "*.js"); do mv "$file" "${file%.*}.cjs"; done
FatihAziz
  • 438
  • 4
  • 11