using the `find` command with -exec for a lot of files, how can I compare the output against a value? - bash

I am trying to iterate over a large number of images and check their 'mean' value using ImageMagick.
The following command finds the images I want to check, and executes the correct command on them.
find `pwd` -type f -name "*.png" -exec /usr/bin/identify -ping -format "%[mean]" info: {} \;
Now I want to compare the output to see if it comes up with a certain value, 942.333
How can I get the output of each value that find returns to check and spit out the filename of any matched image who has the ouput of 942.333 from my command?
Thanks!

Change your identify command so it outputs the filename and the mean, then use grep:
find `pwd` -type f -name "*.png" -exec identify -ping -format "%[mean] %f\n" {} \; | grep "942.333"
Or, if you really have lots of images, you could put all your lovely CPU cores to work and do them in parallel, using GNU Parallel:
find . -name \*.png -print0 | parallel -m -0 'identify -ping -format "%[mean] %f\n" {1}' | grep ...

Related

How to write the wc's stdout into a file?

The below command will show how many characters contains in every file in current directory.
find -name '*.*' |xargs wc -c
I want to write the standout into a file.
find -name '*.*' |xargs wc -c > /tmp/record.txt
It encounter an issue:
wc: .: Is a directory
How to write all the standard output into a file?
Why -name '*.*'? That will not find every file and will find directories. You need to use -type f, and better than piping the result to xargs is using -exec:
find . -type f -maxdepth 1 -exec wc -c {} + > /tmp/record.txt
-maxdepth 1 guarantees that the search won't dive in subdirectories.
I think you maybe meant find |xargs wc -c?
find -name '.' just returns .
Filter only files, if you want only files.
find -type f

Naming files after splitting them with split command within a pipeline

I've been recently dealing with splitting large files and processing them further.
My current pipe is very simple>
find . -type f -size +100M | split -b 100M
But what this does is not exactly what I'm after. I would like splitted files named similarly to input files to split function, for example> inputs of find are>
file1
file2
file3
I would like output in the lines of for example
file101 file102 ...
file201 file202 ...
file301 file302 ...
I tried with >
split -b 100M -d $(find . -type f -size +1000M) $(find . -type f -size +1000M)
but it doesn't work as I wish, it throws error!
Thanks.
split doesn't read the filenames from standard input. You have to give the filename as an argument. You can do that with the -exec option to find. Use the {} placeholder to substitute the filename for both the input file and the output prefix arguments.
find . -type f -size +100M -exec split -b 100M -d {} {} \;

Move output of Find command unix

Im learning unix programming , i want to find all files whose size is greater than 1M an print them into a file.
here is my code
find. -size +1M -print0 | xargs -I -O '{}' mv '{}' files
all sites i have found refer to this one as right one , but it does not work . currently im working on ubuntu
You mis-copied/mis-typed the commend from wherever you found it.
The first {} is the argument to -I.
-O is not an argument to xargs you meant -0 (to go with -print0).
You missed the space between find and . (the current directory).
Which would get you:
find . -size +1M -print0 | xargs -0 -I '{}' mv '{}' files
That being said you don't need xargs here at all since find can execute commands directly.
find . -size +1M -exec mv {} files \+
And it is generally a good idea to test a complicated find command before you run it.
Using find . -size +1M by itself will just print the matching files.
Using
find . -size +1M -ok mv {} files \+
will cause find to prompt you before each execution of the command.

Get the filename from bash script recursively using find

I am trying retrieve the filename from the find command recursively. This command prints all the filenames with full path
> for f in $(find -name '*.png'); do echo "$f";done
> ./x.png
> ./bg.png
> ./s/bg.png
But when i try to just get the name of the file using these commands, it prints
for f in $(find -name '*.png'); do echo "${f##*/}";done
bg.png
and
for f in $(find -name '*.png'); do echo $(basename $f);done
bg.png
It omits other 2 files. I am new to shell scripting. I couln't figure out whats wrong with this one.
EDIT:
THis is what i have actually wanted.
I want to loop through a directory recursively and find all png images
send it to pngnq for RGBA compression
It outputs the new file with orgfilename-nq8.png
send it to pngcrush and rename and generate a new file (org file will be overwritten )
remove new file
i have a code which works on a single directory
for f in *.png; do pngnq -f -n 256 "$f" && pngcrush "${f%.*}"-nq8.png "$f";rm "${f%.*}"-nq8.png; done
I want to do this recursively
Simply do :
find -name '*.png' -printf '%f\n'
If you want to run something for each files :
find -name '*.png' -printf '%f\n' |
while read file; do
# do something with "$file"
done
Or with xargs :
find -name '*.png' -printf '%f\n' | xargs -n1 command
Be sure you cannot use find directly like this :
find -name '*.png' -exec command {} +
or
find -name '*.png' -exec bash -c 'do_something with ${1##*/}' -- {} \;
Search -printf on http://unixhelp.ed.ac.uk/CGI/man-cgi?find or in
man find | less +/^' *-printf'

Piping find to find

I want to pipe a find result to a new find. What I have is:
find . -iname "2010-06*" -maxdepth 1 -type d | xargs -0 find '{}' -iname "*.jpg"
Expected result: Second find receives a list of folders starting with 2010-06, second find returns a list of jpg's contained within those folders.
Actual result: "find: ./2010-06 New York\n: unknown option"
Oh darn. I have a feeling it concerns the format of the output that the second find receives as input, but my only idea was to suffix -print0 to first find, with no change whatsoever.
Any ideas?
You need 2 things. -print0, and more importantly -I{} on xargs, otherwise the {} doesn't do anything.
find . -iname "2010-06*" -maxdepth 1 -type d -print0 | xargs -0 -I{} find '{}' -iname '*.jpg'
Useless use of xargs.
find 2010-06* -iname "*.jpg"
At least Gnu-find accepts multiple paths to search in. -maxdepth and type -d is implicitly assumed.
How about
find . -iwholename "./2010-06*/*.jpg
etc?
Although you did say that you specifically want this find + pipe problem to work, its inefficient to fork an extra find command. Since you are specifying -maxdepth as 1, you are not traversing subdirectories. So just use a for loop with shell expansion.
for file in *2010-06*/*.jpg
do
echo "$file"
done
If you want to find all jpg files inside each 2010-06* folders recursively, there is also no need to use multiple finds or xargs
for directory in 2010-06*/
do
find $directory -iname "*.jpg" -type f
done
Or just
find 2006-06* -type f -iname "*.jpg"
Or even better, if you have bash 4 and above
shopt -s globstar
shopt -s nullglob
for file in 2010-06*/**/*.jpg
do
echo "$file"
done

Resources