LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (http://www.linuxquestions.org/questions/linux-general-1/)
-   -   bash: renaming file extension based on actual file type (http://www.linuxquestions.org/questions/linux-general-1/bash-renaming-file-extension-based-on-actual-file-type-693415/)

alekone 12-28-2008 06:52 AM

bash: renaming file extension based on actual file type
 
hello!
I have some thousands image files with extensions messed up (ie: eps file with .tif extension).

I'm trying to determine the actual content of a file with the file command. that's what I get with the command "file *":
160076_PEZZOLI-77550.TIF: TIFF image data, big-endian
160717_caravFIG50.TIF: PostScript document text conforming at level 3.0 - type EPS
16272_BIETO02.TIF: PostScript document text conforming at level 3.0 - type EPS

I'd like to rename the EPS file with .eps extension.
I don't know how to pipe the "file" command into a grep command to replace the first extension with the correct one.
I mean, if I write "file * | grep EPS" it correctly returns all the tif that are really EPS, but how do I pipe in the filename to rename it with a regular expression?

thank you very much.

pixellany 12-28-2008 07:44 AM

Welcome to LQ!!

First, GREP does not do renaming or replacement--it is strictly a filter

Second, you do not rename using a pipe. You have to use something like "mv oldname newname", where newname includes a variable containing the desired extension.
Example: rename files with the oldname (minus the old extension) in a variable "old", and the desired extension in a variable "ext":
mv $old $old$ext

Here is a generic way to go: (NOT TESTED!!)


Code:

for old in `ls|sed 's/\....$//'`; do    ##loop thru the current directory, removing all instances of "." + any 3 chars at the end of the filename.  (Note--fragile.  Only removes 3-character extensions)
  ext=`file $old|sed 's/.*\(...\)/\1/'`  ##get the filetype using file command---filetype assumed to be the last 3 chars of the output of file.  Assign to the variable "ext"
  mv $old $old.$ext ##rename from the name in "old" to the name in "old". name in "ext"
done   ##end of loop

Note the backtics in two places (not the same as a single quote).

David the H. 12-28-2008 08:02 AM

Here's a simple script I whipped up. It uses if statements to test the output of "file", then renames any matches on TIFF or EPS. It only runs through the files in the current directory.

It could probably be a whole lot better, but it seems to work for me (I didn't test it fully though). You might want to beware of any false positives. If you only want to match one type of file, just remove the unwanted if statement.

Code:

#!/bin/bash

for NAME in $(ls $PWD); do

if [ "$(file $NAME|grep EPS)" ]; then

echo "Renaming ${NAME} to ${NAME%.*}.eps"
mv ${NAME} ${NAME%.*}.eps

elif [ "$(file $NAME|grep TIFF)" ]; then

echo "Renaming ${NAME} to ${NAME%.*}.tif"
mv ${NAME} ${NAME%.*}.tif

fi

done


acid_kewpie 12-28-2008 08:16 AM

Code:

for i in *
do
  ( file $i | grep EPS ) && mv $i $(echo $i | sed s/tif$/eps$/)
done


acid_kewpie 12-28-2008 08:22 AM

me too slow. that's what you get for changing nappies whilst writing posts.

David's is the best there, even if his for loop input is over complex hand and if statements are quite long. bash level substitution is nicer than my spitting things through sed, but i can never remember the syntax.

and backticks are obsolete in preference to $( blah ) for reasons of clarity among others.

alekone 12-28-2008 08:49 AM

thank you very much!
I'll test the second solution that seems easier to me and I'll let you know if it works!

David the H. 12-28-2008 09:06 AM

Quote:

Originally Posted by acid_kewpie (Post 3389316)
David's is the best there, even if his for loop input is over complex hand and if statements are quite long. bash level substitution is nicer than my spitting things through sed, but i can never remember the syntax.

Thank you. But I'm really just an amateur hacking around. I was knew when I wrote it that there must be better ways to go about it. I just went with the first thing I got working. :)

I do love the parameter substitution though. I've just recently discovered it, and it's really convenient and not that hard to understand. The Advanced Bash-Scripting Guide has a reference page for them here, and a longer description here.

BTW, thank you for your example. It was quite educational for me. It looks like I should look more into parentheses grouping myself.

alekone 12-28-2008 09:34 AM

it works perfectly!
should I add quotes " somewhere for compatibility with filenames with spaces in them?
thank you
ale.

David the H. 12-28-2008 10:02 AM

Probably the easiest way to handle files with spaces (other than renaming the files so they don't have spaces, that is ;)), is to temporarily change the IFS (internal field separator) shell variable so that it doesn't recognize spaces as separators.

I've been playing around and I've rewritten my script above to use a case statement instead of if. This makes it more readable and avoids having to call on grep. I've also added code to change the IFS for you. Notice that the temporary IFS value is a carriage return, which is why the end quotes are on the next line.

Code:

#!/bin/bash

OLDIFS=$IFS
IFS="
"

for NAME in $(ls $PWD); do

        case $(file $NAME) in

                *EPS* ) mv $NAME ${NAME%.*}.eps ;;

                *TIFF* ) mv $NAME ${NAME%.*}.tif ;;

                * ) echo "file $NAME not changed." ;;

        esac

done

IFS=$OLDIFS

exit 0


alekone 12-28-2008 10:12 AM

wow!
that's a really interesting solution.
thank you


All times are GMT -5. The time now is 05:13 AM.