bash: renaming file extension based on actual file type
Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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?
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).
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
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.
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.
Last edited by David the H.; 12-28-2008 at 08:19 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
Last edited by David the H.; 12-28-2008 at 09:04 AM.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.