Batch renaming files in command line and Xargs
Solution 1
how do i rename the file so that I can just have one extension.
cd dir/with/messedup/files
for file in *.png.jpg; do
mv "$file" "${file%.png.jpg}.jpg"
done
in the future, using xargs, how do I change the extension of the file simular to second command?
To my knowledge, that can't be done. The best way to do it would be to use a for-loop with parameter substitution much like the one above:
for file in *.png; do
convert "$file" -resize "${file%.png}.jpg"
done
If you have files in subdirectories that you want converted, then you can pipe find
to a while read
loop:
find . -type f -name '*.png' |
while read file; do
convert "$file" -resize "${file%.png}.jpg"
done
NOTE: It's generally considered a bad idea to use the output of ls
in a shell script. While your example might have worked fine, there are lot's of examples where it doesn't. For instance, if your filenames happened to have newlines in them (which unix allows), ls
probably won't escape those for you. (That actually depends on your implementation, which is another reason not to use ls
in scripts; it's behavior varies greatly from one box to the next.) You'll get more consistent results if you either use find
in a while-read loop or file globbing (e.g. *.png
) in a for loop.
Solution 2
This can be also be done with xargs
and sed
to change the file extension.
ls | grep \.png$ | sed 'p;s/\.png/\.jpg/' | xargs -n2 mv
You can print the original filename along with what you want the filename to be. Then have xargs use those two arguments in the move command. For the one-liner, I also added a grep to filter out anything not a *.png file.
Solution 3
Coming late to the party, but here's how you can rename files with xargs. Say you have a bunch of files named fileN.svg.png and you want to name them fileN.png where N could be a series of integers:
ls *.svg.png | xargs basename -s .svg.png | xargs -I {} mv {}.svg.png {}.png
The first xargs uses basename to strip off both .svg and .png to get a just filenameN
. The second xargs receives that bare name and uses replacement to rename the file.
Solution 4
To clean up your error, try the rename
utility. Check the manpage for details.
In your case, you'd do rename '.png.jpg' '.jpg' ./*
if your current directory is set appropriately.
Since you have convert
available, I'm assuming you have mogrify
too (imagemagick
suite). Whenever I want to do this, I copy the files into a different directory and use mogrify
instead. I usually need this only for resizing, but if you change the image format aswell, mogrify
will handle the filenames (make new files with proper filenames).
You would use it as mogrify -format jpg -resize [size] ./*.png
. I'm not sure what -resize
without geometry arguments is supposed to do. It isn't documented and doesn't work on my machine.
As Tim Pote reasoned, I don't think you can make xargs handle filenames and extensions separately.
Solution 5
I'm late to this party by about 3 years, I just had a similar problem which I figured out myself. I had a list of png files which I converted using inkscape, because ImageMagick's svg support is poor.
I originally converted them by doing:
find . -name "*.svg" -exec inkscape {} --export-png={}.png
Which of course led to the same issue like posted above.
file1.svg
file1.svg.png
file2.svg
file2.svg.png
file3.svg
file3.svg.png
file4.svg
file4.svg.png
I wanted to rename *.svg.png to *.png, this is what I wound up with...
find . -name "*.svg.png" -print0 | sed 's/.svg.png//g' | xargs -0 -I namePrefix mv namePrefix.svg.png namePrefix.png
This does three things:
- find in this directory files named *.svg.png, the -print0 prints to standard output
- sed modifies the standard output, basically swap .svg.png with nothing, so I'd get: file1/file2/file3/file4
- xargs -0 to get the data from sed, -I references the filename w/o the extension, then mv original filename to new filename. The word namePrefix isn't anything special, just wanted to make it clear.
EDIT
I realize now this is the most convoluted way to do this. One can simply use the rename command.
rename 's/svg\.png/.png/' *
Cripto
Updated on July 10, 2022Comments
-
Cripto almost 2 years
So, I have the following structure:
. .. a.png b.png c.png
I ran a command to resize them
ls | xargs -I xx convert xx -resize xx.jpg
Now my dir looks like this
. .. a.png.jpg a.png b.png.jpg b.png c.png.jpg c.png
The firs question is, how do i rename the file so that I can just have one extension. Not two. (basically, how do I clean up my original mistake)?
The second question is, in the future, using xargs, how do I change the extension of the file simular to second command? -
Matej almost 12 yearsI think piping
find
into awhile
loop is genius, I've never seen it before. -
rturrado over 8 yearsBeautiful! Didn't know about
sed 'p'
nor aboutxargs -n2
. -
adrianN almost 8 yearsDoes this work if the paths contain spaces? I don't think so.
find . -name "*.png" -print0 | sed 'p;s/\.png/\.jpg/' | xargs -0 -n2 mv
is better I think. -
Alan Zeino over 5 years
rename
definitely was the simplest way for me:$ find . -name *[email protected] | rename 's/_12_0\@2x.png/_12_0\@3x.png/' --stdin
(in this case, I wanted to change the2x
to `3x in the file name) -
Phil over 5 yearsI recommend using "sed -z", if you use null-byte actions. Otherwise sed will interprete the stream as binary. Less performant and more error prone.
-
meh over 5 yearsBy far the best answer here.
-
james-see over 4 yearsYou are never late on the internet. This was super helpful, I used a modified version of your one-liner. Thanks
-
soMuchToLearnAndShare almost 4 yearsthis only works if the command is run under the folder which these files are located... .my attempt to use this, the mv command complains as it will not be able to 'stat' the file,
-
Alexander Vasiljev over 3 yearsI'd start with
... | xargs -0 -n2 echo mv
first, and proceed with... | xargs -0 -n2 mv
if result is correct. -
CervEd about 3 yearsany reason to use
mv
instead ofrename
? -
Ferd about 2 years@adrianN Does
find ... -print0
work with GNU sed? Even though this question is tagged #linux, this version works for me with BSD sed on macOS:find . -name "*.png" | sed -e 'p;s/\.png/\.jpg/' | tr '\n' '\0' | xargs -0 -n2 mv
-
damd almost 2 years@CervEd Not all systems have
rename
, and not all systems have the samerename