views:

1767

answers:

6

I have a few directories and sub-directories containing files with no file extension. I want to add .jpg to all the files contained within these directories. I've seen bash scripts for changing the file extension but not for just adding one. It also needs to be recursive, can someone help please?

+1  A: 

like this,

for f in $(find . -type f); do mv $f ${f}.jpg; done

I am not expecting you have space separated file names,
If you do, the names will need to be processed a bit.

If you want to execute the command from some other directory,
you can replace the find . with find /target/directory.

nik
This is missing a 'do' and if there are spaces in the filename, it may better to quote the filename:for f in $(find . -type f); do mv "$f" "${f}.jpg"; done
Al
and presumably i would run that from within the top level directory?
seengee
@seengee: yes. Note that this command also misses the dash in `-type`.
Stephan202
I had to go somewhere and typed too fast... fixing now.
nik
+9  A: 

Alternative command without an explicit loop (man find):

find . -type f -exec mv '{}' '{}'.jpg \;

Explanation: this recursively finds all files (-type f) starting from the current directory (.) and applies the move command (mv) to each of them. Note also the quotes around {}, so that filenames with spaces (and even newlines...) are properly handled.

Stephan202
In particular, this one works better if there are a huge number of files in the directory structure (causing bash to get upset about the length of the list of files to iterate over).
Al
thanks for the answer and the recommendation!
seengee
@Al, if you refer to a `for` loop upsetting bash to iterate over a list of files, that is not correct. The bash `for` loop iteratively issues each `mv` command.
nik
Question: Does `find` first set up a list of files *before* it executes the `-exec` statement? I guess so, but want to get this point clear before coding infinite loops.
Boldewyn
@Boldewyn, I think it will be prudent to avoid working on symbolic links (with a `-P`) if you suspect a possible loop.
nik
Though, symbolic links are skipped by default I think.
nik
this command will find files with extension as well. Is that what OP wants?
ghostdog74
@ghostdog74: Since he accepted this answer, the above apparently did the trick. Otherwise, as you mentioned below, adding `-not -name "*.*"` will do the trick.
Stephan202
In my version of bash, the quotes around {} have no effect on how "find" handles filenames with spaces, etc around them. As you've written it, the "find" command will not even see the quotes: they're handled by bash
Adrian Pronk
+5  A: 

this will find files without extension and add your .jpg

find /path -type f -not -name "*.*" -exec mv "{}" "{}".jpg \;
ghostdog74
+1 because this skips files which already have an extension.
Stephan202
A: 

rename

not sure that it can rename files without extensions (I'm on windows 7 right now)

dfa
it can, but it will also rename directories, and there is no way to tell it to work recursively in sub-directories (at least with the version I have on Ubuntu).
mirod
I know at least of two different commands called `rename`, one a C program included in util-linux-ng and one a Perl program (by Wall himself) on our university's Debian machines. Actually, none of both do recursion.
Boldewyn
+1  A: 

This is a little late, but I thought I would add that a better solution (although maybe less readable) than the ones so far might be:

find /path -type f -not -name "." -print0 | xargs -0 rename 's/(.)$/$1.jpg/'

Using the find | xargs pattern generally results in more efficient execution, as you don't have to fork a new process for each file.

Note that this requires the version of rename found in Debian-flavored distros (aka prename), rather than the traditional rename. It's just a tiny perl script, though, so it would be easy enough to use the command above on any system.

Chad Huneycutt
thanks for the info
seengee
A: 

On this same topic, how can I strip off one extension, as I accidentally renamed all files to .ext.ext. Note: the extensions are pdf so it's filename.pdf.pdf and I just need .pdf of course.

Thanks for your help!

::: EDIT :::

Found the solution for anyone in need of the fix:

ls *.pdf.pdf|sed -e's/.pdf.pdf//'|xargs -i{} mv {}.pdf.pdf {}.pdf

You may get a warning message upon executing the script, but it still works, I guess it was luck since I am strapped for time brain power. But it DOES work.

Brian