bash scripting - trouble renaming files in subdirectories using find / rename - bash

I have a large series of directories and subdirectories with many jpgs in them. I need to do two things:
Create a copy of each jpg found within it's own subdirectory
Rename this copied jpg such that apple.jpg becomes apple_m.jpg
I have tried to run the following commands in order:
//this creates a copy of every jpg found and appends '_m' to the end of it
find . -name '*.jpg' -execdir cp {} {}_m \;
//now again find everything with 'jpg_m' at the end and rename it as filename_m.jpg
find . -name '*.jpg_m' -execdir rename -v 's/\.jpg_m/_m\.jpg/' {} \;
However the 2nd command does'nt seem to work, can someone please explain what I'm doing wrong?
Thanks,
Adi

To rename files, you can simply use it this way
rename ".jpg_m" "_m.jpg" files_to_rename
so, if you want to copy and rename, you can rename it this way:
find . -name "*.jpg_m" -execdir rename ".jpg_m" "_m.jpg" {} \;

Why don't you do it in one pass?
find . -name '*.jpg' -exec cp {} m_{} \; -exec rename "m_" "" {} \;

Related

Copy all empty files into a folder with command line

I am trying to copy all empty files from the home directory into a folder that is on the desktop, using this:
find ~ -empty -exec cp {} /desktop/emptyfolder \;
However, I can't make it work.
Are there any other possible solutions to achieve this? Or maybe to write a bash script that could do this?
Add -type f to the find command to force it to search for files and not directories and so:
find ~ -empty -type f -exec cp {} /desktop/emptyfolder \;

rename folder/directory recursively

I want to rename folder/directory names recursively and found this solution on SO. However this command has no effect
find . -type f -exec rename 's/old/new/' '{}' \;
Is that a correct command?
find . -depth -name '*a_*' -execdir bash -c 'mv "$0" "${0//a_/b_}"' {} \;
The -depth switch is important so that the directory content is processed before the directory itself! otherwise you'll run into problems :).
100% safe regarding filenames with spaces or other funny symbols.

Changing names for all files in subdirectroies

I have a folder with a number of subfolders. Each of the subfolders consists of several files without extension.
I need to add extension .cel to each file in subfolders.
How can I do it using bash?
find to the rescue:
find /your/folder -type f -exec mv {} {}.cel \;
Explanation: find obtains all files inside the /your/folder structure. From all the results obtained, it performs the mv command. It makes the file XXX to be moved to XXX.cel, which is another way of renaming it.
If you have rename then using that with find should do the trick:
find . -type f -exec rename -v 's/$/\.cel/' {} \;

shell script for listing all images in current and subfolder and copy them into one folder?

I have some folder hierarchy, in some of the folders there are images, I need a shell script which can list all images and copy them into one specified folder, where listing them is not important, I just want to copy all images into a folder?
I know I can
ls -R *.png
but how do I copy them all to one folder?
Thanks!
Update: As glenn jackman has pointed out, this would be slightly more efficient to use over the answer I provided:
file . -type f -name \*.png | xargs cp -t destination
For the explanation, see glenn's comments that follow this answer.
One way is to use find:
find . -type f -name "*.png" -exec cp {} ~/path/to/your/destination/folder \;
Explanation:
find is used to find files / directories
. start finding from the current working directory (alternatively, you can specify a path)
-type f: only consider files (as opposed to directories)
-name "*.png": only consider those with png extension
-exec: for each such result found, do something (see below)
cp {} ~/path/to/your/destination/folder \;: this is the do something part: copy each such result found (substituted into the {}) to the destination specified.
To copy multiple file patterns in single go we can use -regex instead -name
find . -type f -regex '.*\(jpg\|jpeg\|png\|gif\|mp4\|avi\|svg\|mp3\|vob\)' -exec cp {} /path/to/your/destination/folder \;

Recursively unzip files and then delete original file, leaving unzipped files in place from shell

I've so far figured out how to use find to recursively unzip all the files:
find . -depth -name `*.zip` -exec /usr/bin/unzip -n {} \;
But, I can't figure out how to remove the zip files one at a time after the extraction. Adding rm *.zip in an -a -exec ends up deleting most of the zip files in each directory before they are extracted. Piping through a script containing the rm command (with -i enabled for testing) causes find to not find any *.zips (or at least that's what it complains). There is, of course, whitespace in many of the filenames but at this point syntaxing in a sed command to add _'s is a bit beyond me. Thank for your help!
have you tried:
find . -depth -name '*.zip' -exec /usr/bin/unzip -n {} \; -exec rm {} \;
or
find . -depth -name '*.zip' -exec /usr/bin/unzip -n {} \; -delete
or running a second find after the unzip one
find . -depth -name '*.zip' -exec rm {} \;
thx for the 2nd command with -delete! helped me a lot..
just 2 (maybe helpful) remarks from my side:
-had to use '.zip' instead of `.zip` on my debian system
-use -execdir instead of -exec > this will extract each zip file within its current folder, otherwise you end up with all extracted content in the dir you invoked the find cmd.
find . -depth -name '*.zip' -execdir /usr/bin/unzip -n {} \; -delete
THX & Regards,
Nord
As mentioned above, this should work.
find . -depth -name '*.zip' -execdir unzip -n {} \; -delete
However, note two things:
The -n option instructs unzip to not overwrite existing files. You may not know if the zip files differ from the similarly named target files. Even so, the -delete will remove the zip file.
If unzip can't unzip the file--say because of an error--it might still delete it. The command will certainly remove it if -exec rm {} \; is used in place of -delete.
A safer solution might be to move the files following the unzip to a separate directory that you can trash when you're sure you have extracted all the files successfully.
Unzip archives in subdir based on the file name (../file.zip -> ../file/..):
for F in $(find . -depth -name *.zip); do unzip "$F" -d "${F%.*}/" && rm "$F"; done
I have a directory filling up with zipped csv files. External processes are writing new zipped files to it often. I wish to bulk unzip and remove the originals as you do.
To do that I use:
unzip '*.zip'
find . | sed 's/$/\.zip/g' | xargs -n 1 rm
It works by searching and expanding all zip files presently in the directory. Later, after it finishes there are potentially new unzipped new files mixed in there too that are not to be deleted yet.
So I delete by finding successfully unzipped *.csv files, and using sed to regenerate the original filenames for deletion which is then fed to rm via the xargs command.

Resources