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

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

Related

How can I diff two directories in bash recursively for only 1 file name?

Currently I am trying this:
diff -r /develop /us-prod
which shows all the differences between the two, but all I really care about here is a file named schema.json, which is guaranteed to be there in all directories, but this file can be different.
I want to diff these two directories, but only if the file name is schema.json.
I see that you can do -x to exclude files, but it is difficult to say which other files could be in there.
There are some guaranteed files to be there, but some are not. Is there more an "inclusion" than an exclude?
You can try this :
find /develop -type f -name schema.json -exec bash -c\
'diff "$1" "/us-prod${1#/develop}"' _ {} \;
Assuming the both directories have just one schema.json file for each directory
including their subdirectories, would you please try:
diff $(find /develop -type f -name schema.json) $(find /us-prod -type f -name schema.json)

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

Bash script for removing specific file from certain subdirectories

On a unix server, I'm trying to figure out how to remove a file, say "example.xls", from any subdirectories that start with v0 ("v0*").
I have tried something like:
find . -name "v0*" -type d -exec find . -name "example.xls" -type f
-exec rm {} \;
But i get errors. I have a solution but it works too well, i.e. it will delete the file in any subdirectory, regardless of it's name:
find . -type f -name "example.xls" -exec rm -f {} \;
Any ideas?
You will probably have to do it in two steps -- i.e. first find the directories, and then the files -- you can use xargs to make it in a single line, like
find . -name "v0*" -type d | \
xargs -l -I[] \
find [] -name "example.xls" -type f -exec rm {} \;
what it does, is first generating a list of viable directory name, and let xargs call the second find with the names locating the file name within that directory
Try:
find -path '*/v0*/example.xls' -delete
This matches only files named example.xls which, somewhere in its path, has a parent directory name that starts with v0.
Note that since find offers -delete as an action, it is not necessary to invoke the external executable rm.
Example
Consider this directory structure:
$ find .
.
./a
./a/example.xls
./a/v0
./a/v0/b
./a/v0/b/example.xls
./a/v0/example.xls
We can identify files example.xls who have one of their parent directories named v0*:
$ find -path '*/v0*/example.xls'
./a/v0/b/example.xls
./a/v0/example.xls
To delete those files:
find -path '*/v0*/example.xls' -delete
Alternative: find only those files directly under directory v0*
find -regex '.*/v0[^/]*/example.xls'
Using the above directory structure, this approach returns one file:
$ find -regex '.*/v0[^/]*/example.xls'
./a/v0/example.xls
To delete such files:
find -regex '.*/v0[^/]*/example.xls' -delete
Compatibility
Although my tests were performed with GNU find, both -regex and -path are required by POSIX and also supported by OSX.

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.

Resources