Imagemagick with find in bash script : output in current folder - bash

I have subfolders with png images inside. I want to convert them to jpeg with a static name (there is only one image per folder). The images need to be outputted in the same folder as the original image.
This bash script
#! /bin/sh
find . -type f -name '*.png' -exec convert "{}" *OPTIONS* mydefinedname.jpg \;
doesn't work because the output is always the root folder, so it erases each previous jpeg with the current one.
Ho to tell convert ? The help file isn't clear on this point.

Instead of -exec, use -execdir, which runs the command in the directory the file is in, rather than the current working directory:
find . -type f -name '*.png' -execdir convert "{}" *OPTIONS* mydefinedname.jpg \;

Related

Move all files in subdirectories of a specific name up one directory level

I've run a batch process to resize and optimize all images within a directory and subdirectories. Unfortunately, Photoshop CC doesn't have an option (that I'm aware of) to overwrite the existing images and instead creates a 'JPEG' directory anywhere it processes images and writes the processed images there. The number of images is relatively large (~2000 images) and they're divided into hundreds of subdirectories, so manually moving the images to overwrites the existing ones is out of the question.
How can I move all of the processed images in the 'JPEG' directories up a level to overwrite the original images? The closes I think I've come is this:
find . -type d -name "JPEG" -exec cd {} \; && find . -type f -name "*.jpg" -exec mv -v {} .. \;
...but that drops all the images a level up from my current directory.
Can some one sort me out?
Your cd only affects a subprocess which changes to the directory and dies, while its parent process remains unaffected.
Anyway, switching to a directory is rarely necessary or useful; just use the path directly in the mv command.
find . -type d -name "JPEG" -exec mv -v {}/*.jpg {}/.. \;
(Not in a place where I can test right now, but I guess the wildcard needs a shell, too:
find . -type d -name "JPEG" -exec sh -c 'mv -v {}/*.jpg {}/..' \;
Untested, obviously.)
backup your image directory before using the following script.
CURRENT_DIR=$(pwd)
for x in $(find -type d -name 'JPEG')
do
cd $x && mv -v *.jpg .. # you can use `cp` instead of `mv`, then remove JPEG directory.
cd $CURRENT_DIR
done

How do I recursively find files with specific names and join using ImageMagick in Terminal?

I have created an ImageMagick command to join images with certain names:
convert -append *A_SLIDER.jpg *B_SLIDER.jpg out.jpg
I have lots of folders with files named *A_SLIDER.jpg and *B_SLIDER.jpg next to each other (only ever one pair in a directory).
I would like to recursively search a directory with many folders and execute the command to join the images.
If it is possible to name the output image based on the input images that would be great e.g.
=> DOGS_A_SLIDER.jpg and DOGS_B_SLIDER.jpg would combine to DOGS_SLIDER.jpg
Something like this, but back up first and try on a sample directory only!
#!/bin/bash
find . -name "*A_SLIDER*" -execdir bash -c ' \
out=$(ls *A_SLIDER*);
out=${out/_A/}; \
convert -append "*A_SLIDER*" "*B_SLIDER*" $out' \;
Find all files containing the letters "A_SLIDER" and go to the containing directory and start bash there. While you are there, get the name of the file, and remove the _A part to form the output filename. Then execute ImageMagick convert with the _A_ and the corresponding _B_ files to form the output file.
Or, a slightly more concise suggestion from #gniourf_gniourf... thank you.
#!/bin/bash
find . -name "*A_SLIDER.jpg" -type f -execdir bash -c 'convert -append "$1" "${1/_A_/_B_}" "${1/_A/}"' _ {} \;
The "find" command will recursively search folders:
$ find . -name "*.jpg" -print
That will display all the filenames. You might instead want "-iname" which does case-insensitive filename matching.
You can add a command line with "-exec", in which "{}" is replaced by the name of the file. You must terminate the command line with "\;":
$ find . -name "*.jpg" -exec ls -l {} \;
You can use sed to edit the name of a file:
$ echo DOGS_A_SLIDER.jpg | sed 's=_.*$=='
DOGS
Can you count on all of your "B" files being named the same as the corresponding "A" files? That is, you will not have "DOGS_A_SLIDER.jpg" and "CATS_A_SLIDER.jpg" in the same directory. If so, something like the following isn't everything you need, but will contribute to your solution:
$ find . -type f -name "*.jpg" -exec "(echo {} | sed 's=_.*==')" \;
That particular sed script will do the wrong thing if you have any directory names with underscores in them.
"find . -type f" finds regular files; it runs modestly faster than without the -type. Use "-d" to find directories.

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

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_" "" {} \;

Move only files recursively from multiple directories into one directory with mv

I currently have ~40k RAW images that are in a nested directory structure. (Some folders have as many as 100 subfolders filled with files.) I would like to move them all into one master directory, with no subfolders. How could this be accomplished using mv? I know the -r switch will copy recursively, but this copies folders as well, and I do not wish to have subdirectories in the master folder.
If your photos are in /path/to/photos/ and its subdirectories, and you want to move then in /path/to/master/, and you want to select them by extension .jpg, .JPG, .png, .PNG, etc.:
find /path/to/photos \( -iname '*.jpg' -o -iname '*.png' \) -type f -exec mv -nv -t '/path/to/master' -- {} +
If you don't want to filter by extension, and just move everything (i.e., all the files):
find /path/to/photos -type f -exec mv -nv -t '/path/to/master' -- {} +
The -n option so as to not overwrite existing files (optional if you don't care) and -v option so that mv shows what it's doing (very optional).
The -t option to mv is to specify the target directory, so that we can stack all the files to be moved at the end of the command (see the + delimiter of -exec). If your mv doesn't support -t:
find /path/to/photos \( -iname '*.jpg' -o -iname '*.png' \) -type f -exec mv -nv -- {} '/path/to/master' \;
but this will be less efficient, as one instance of mv will be created for each file.
Btw, this moves the files, it doesn't copy them.
Remarks.
The directory /path/to/master must already exist (it will not be created by this command).
Make sure the directory /path/to/master is not in /path/to/photos. It would make the thing awkward!
Make use of -execdir option of find:
find /path/of/images -type f -execdir mv '{}' /master-dir \;
As per man find:
-execdir utility [argument ...] ;
The -execdir primary is identical to the -exec primary with the exception that
utility will be executed from the directory that holds the current
file. The filename substituted for the string ``{}'' is not qualified.
Since -execdir makes find execute given command from each directory therefore only base filename is moved without any parent path of the file.
find <base location of files> -type -f -name \*\.raw -exec mv {} master \;
If your hierachy is only one level deep, here is another way using the automated tools of StringSolver:
mv -a firstfolder/firstfile.raw firstfile.raw
The -a options immediately applies the similar transformation to all similar files at a nesting level 1 (i.e. for all other subfolders).
If you do not trust the system, you can use other options such as -e to explain the transformation or -t to test it on all files.
DISCLAIMER: I am a co-author of this work for academic purposes, and working on a bash script renderer. But the system is already available for testing purposes.

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 \;

Resources