How to use find command to find all files with extensions from list? - unix

I need to find all image files from directory (gif, png, jpg, jpeg).
find /path/to/ -name "*.jpg" > log
How to modify this string to find not only .jpg files?

find /path/to -regex ".*\.\(jpg\|gif\|png\|jpeg\)" > log

find /path/to/ \( -iname '*.gif' -o -iname '*.jpg' \) -print0
will work. There might be a more elegant way.

find -E /path/to -regex ".*\.(jpg|gif|png|jpeg)" > log
The -E saves you from having to escape the parens and pipes in your regex.

find /path/to/ -type f -print0 | xargs -0 file | grep -i image
This uses the file command to try to recognize the type of file, regardless of filename (or extension).
If /path/to or a filename contains the string image, then the above may return bogus hits. In that case, I'd suggest
cd /path/to
find . -type f -print0 | xargs -0 file --mime-type | grep -i image/

find /path -type f \( -iname "*.jpg" -o -name "*.jpeg" -o -iname "*gif" \)

On Mac OS use
find -E packages -regex ".*\.(jpg|gif|png|jpeg)"

In supplement to #Dennis Williamson 's response above, if you want the same regex to be case-insensitive to the file extensions, use -iregex :
find /path/to -iregex ".*\.\(jpg\|gif\|png\|jpeg\)" > log

find -regex ".*\.\(jpg\|gif\|png\|jpeg\)"

in case files have no extension we can look for file mime type
find . -type f -exec file -i {} + | awk -F': +' '{ if ($2 ~ /audio|video|matroska|mpeg/) print $1 }'
where (audio|video|matroska|mpeg) are mime types regex
&if you want to delete them:
find . -type f -exec file -i {} + | awk -F': +' '{ if ($2 ~ /audio|video|matroska|mpeg/) print $1 }' | while read f ; do
rm "$f"
done
or delete everything else but those extensions:
find . -type f -exec file -i {} + | awk -F': +' '{ if ($2 !~ /audio|video|matroska|mpeg/) print $1 }' | while read f ; do
rm "$f"
done
notice the !~ instead of ~

Adding -regextype posix-extended option only worked in my case:
sudo find . -regextype posix-extended -regex ".*\.(css|js|jpg|jpeg|png|ico|ttf|woff|svg)" -exec chmod 0640 {} \;

Related

Searching for particular files in a directory non-recursively using find. AIX

I have a script which has the following command. I am trying to edit this in such a way that it only searches the files in the directory of the path without going in the subdirectories. That is not recursive search
find {Path} -name "cor*" -type f -exec ls -l {} \;
Example: The command should give cor123.log only and not cor456.log. Currently it gives both
<Path>
..cor123.log
<directory>
..cor456.log
I tried using -maxdepth but it's not supported in AIX. -prune and -depth didn't help either.
Will appreciate any help. Thanks
You can use
find . -name . -o -prune
to find files and directories non-recursively.
So in your case this one will work:
find . -name . -o -prune -name 'cor*' -type f -exec ls -l {} \;
Do you need find for selecting files only?
When you know that all files starting with cor are regula files, you can use
ls -l ${Path}/cor*
or
ls -l ${Path}/cor*.log
When you need the -type f, you can try to filter the results.
The filename can not have a /, so remove everything with an / after the Path.
We do not know the last char of ${Path}. It can be /, which will make the grep -Ev "${Path}/.*/" filter useless. After the Path at least one character is needed before looking for the next /.
find "${Path}" -name "cor*" -type f 2>/dev/null| grep -Ev "${Path}..*/" | xargs -ls
Late answer but may save some. In aix
find /some/directory/* -prune -type f -name *.log
For instance make your path have the last forward slash with a wildcard then -prune
/*
find /some/directory/* -prune -name "cor*" -type f -exec ls -l {} \
Tested.

unix find command in terminal does not work

I need to place a command that will search for all files in the current directory as well as in its sub-directories - ending by ~, and/or all files that start or end by #. The command line will show and erase all files found. Only one command is allowed: no ’;’ or ’&&’ or other shenanigans.
here is my command:
find . -name "#*" -o -name "*#" -o -name "*~" -print -delete
but it erases only the files ending in ~
You forgot to enclose the conditions with parenthesis (). This means that only the last condition will trigger the actions -print and -delete.
The default is and -a, which would not require the parenthesis, that's why most find commands such as find -type f -name "pattern" -print works without parenthesis.
You should try:
find . \( -name "#*" -o -name "*#" -o -name "*~" \) -print -delete
How about -print0 primary in conjunction with xargs -0'' like this .
find . -type f -print0 | xargs -0 rm
za:temp za$ ls
file.txt file.txt~
za:temp za$ find . -name "*~" -print0 | xargs -0 rm
za:temp za$ ls
file.txt
Or with xargs -I {} plus your comand which does the same thing .
# xargs -I {} to capture the value of find
find . -iname *something* | xargs -I {} rm {}
edit : if you can't see the files that start with # using find . then the files have spaces within the name of the file(s) like # file.txt. you will need to find files with spaces with something like find . -name "* *" and then remove the spaces.

Need help in unix find with xargs command

Am trying to delete files with below find command, few files are not deleting and all those file names are like: filname.123.log.
I can't rename or can't do any thing on file name just need to delete
command
$ find /BASE/CODE/LOGS_BACK -type f -mtime +60 | xargs rm -f
xargs: unmatched single quote; by default quotes are special to xargs unless you use the -0 option
I googled and try with the below command but it is giving different error.
$ find /BASE/CODE/LOGS_BACK -type f -mtime +60 | xargs -0 rm -f
xargs: argument line too long
Can you please help regarding this?
using -0 option in xargs means using -print0 option in find :
find /BASE/CODE/LOGS_BACK -type f -mtime +60 -print0 | xargs -0 rm -f
Then all results of find will be ended with '\0' NUL char and xargs will regenerate list correctly by parsing with same char.
find can directly execute a command for each result:
$ find /BASE/CODE/LOGS_BACK -type f -mtime +60 -exec rm -f {} \;
{} is replaced with each matching filename. \; end the command.
This is the fastest way to achieve what you want:
find /BASE/CODE/LOGS_BACK -type f -mtime +60 -exec rm -f {} +
Note the ending + which does the same job as xargs.

Collect .txt and .log files using find

I currently have this script to compress log files:
find . -name '*.log' -print0 | xargs -0 tar zcf $file
Currently finds and compress all the *.log files. I would like to modify it to include also all the ".txt" files but I don't know how, this should be fairly simple right?
find . -type f \( -name "*.log" -o -name "*.txt" \) -exec tar zcf "$file" {} +
Alternatively:
find . -type f -regex ".*\.\(txt\|log\)$" -exec tar zcf "$file" {} +
No need for xargs if your version of find is POSIX compliant and can have it's -exec command terminated with a + (most can)

How do I get the find command to print out the file size with the file name?

If I issue the find command as follows:
find . -name *.ear
It prints out:
./dir1/dir2/earFile1.ear
./dir1/dir2/earFile2.ear
./dir1/dir3/earFile1.ear
I want to 'print' the name and the size to the command line:
./dir1/dir2/earFile1.ear 5000 KB
./dir1/dir2/earFile2.ear 5400 KB
./dir1/dir3/earFile1.ear 5400 KB
find . -name '*.ear' -exec ls -lh {} \;
just the h extra from jer.drab.org's reply. saves time converting to MB mentally ;)
You need to use -exec or -printf. Printf works like this:
find . -name *.ear -printf "%p %k KB\n"
-exec is more powerful and lets you execute arbitrary commands - so you could use a version of 'ls' or 'wc' to print out the filename along with other information. 'man find' will show you the available arguments to printf, which can do a lot more than just filesize.
[edit] -printf is not in the official POSIX standard, so check if it is supported on your version. However, most modern systems will use GNU find or a similarly extended version, so there is a good chance it will be implemented.
A simple solution is to use the -ls option in find:
find . -name \*.ear -ls
That gives you each entry in the normal "ls -l" format. Or, to get the specific output you seem to be looking for, this:
find . -name \*.ear -printf "%p\t%k KB\n"
Which will give you the filename followed by the size in KB.
Using GNU find, I think this is what you want. It finds all real files and not directories (-type f), and for each one prints the filename (%p), a tab (\t), the size in kilobytes (%k), the suffix " KB", and then a newline (\n).
find . -type f -printf '%p\t%k KB\n'
If the printf command doesn't format things the way you want, you can use exec, followed by the command you want to execute on each file. Use {} for the filename, and terminate the command with a semicolon (;). On most shells, all three of those characters should be escaped with a backslash.
Here's a simple solution that finds and prints them out using "ls -lh", which will show you the size in human-readable form (k for kilobytes and M for megabytes):
find . -type f -exec ls -lh \{\} \;
As yet another alternative, "wc -c" will print the number of characters (bytes) in the file:
find . -type f -exec wc -c \{\} \;
find . -name '*.ear' -exec du -h {} \;
This gives you the filesize only, instead of all the unnecessary stuff.
Awk can fix up the output to give just what the questioner asked for. On my Solaris 10 system, find -ls prints size in KB as the second field, so:
% find . -name '*.ear' -ls | awk '{print $2, $11}'
5400 ./dir1/dir2/earFile2.ear
5400 ./dir1/dir2/earFile3.ear
5400 ./dir1/dir2/earFile1.ear
Otherwise, use -exec ls -lh and pick out the size field from the output.
Again on Solaris 10:
% find . -name '*.ear' -exec ls -lh {} \; | awk '{print $5, $9}'
5.3M ./dir1/dir2/earFile2.ear
5.3M ./dir1/dir2/earFile3.ear
5.3M ./dir1/dir2/earFile1.ear
Try the following commands:
GNU stat:
find . -type f -name *.ear -exec stat -c "%n %s" {} ';'
BSD stat:
find . -type f -name *.ear -exec stat -f "%N %z" {} ';'
however stat isn't standard, so du or wc could be a better approach:
find . -type f -name *.ear -exec sh -c 'echo "{} $(wc -c < {})"' ';'
Just list the files (-type f) that match the pattern (-name '*.ear) using the disk-usage command (du -h) and sort the files by the human-readable file size (sort -h):
find . -type f -name '*.ear' -exec du -h {} \; | sort -h
Output
5.0k ./dir1/dir2/earFile1.ear
5.4k ./dir1/dir2/earFile2.ear
5.4k ./dir1/dir3/earFile1.ear
I struggled with this on Mac OS X where the find command doesn't support -printf.
A solution that I found, that admittedly relies on the 'group' for all files being 'staff' was...
ls -l -R | sed 's/\(.*\)staff *\([0-9]*\)..............\(.*\)/\2 \3/'
This splits the ls long output into three tokens
the stuff before the text 'staff'
the file size
the file name
And then outputs tokens 2 and 3, i.e. output is number of bytes and then filename
8071 sections.php
54681 services.php
37961 style.css
13260 thumb.php
70951 workshops.php
Why not use du -a ? E.g.
find . -name "*.ear" -exec du -a {} \;
Works on a Mac
This should get you what you're looking for, formatting included (i.e. file name first and size afterward):
find . -type f -iname "*.ear" -exec du -ah {} \; | awk '{print $2"\t", $1}'
sample output (where I used -iname "*.php" to get some result):
./plugins/bat/class.bat.inc.php 20K
./plugins/quotas/class.quotas.inc.php 8.0K
./plugins/dmraid/class.dmraid.inc.php 8.0K
./plugins/updatenotifier/class.updatenotifier.inc.php 4.0K
./index.php 4.0K
./config.php 12K
./includes/mb/class.hwsensors.inc.php 8.0K
You could try this:
find. -name *.ear -exec du {} \;
This will give you the size in bytes. But the du command also accepts the parameters -k for KB and -m for MB. It will give you an output like
5000 ./dir1/dir2/earFile1.ear
5400 ./dir1/dir2/earFile2.ear
5400 ./dir1/dir3/earFile1.ear
find . -name "*.ear" | xargs ls -sh
$ find . -name "test*" -exec du -sh {} \;
4.0K ./test1
0 ./test2
0 ./test3
0 ./test4
$
Scripter World reference
find . -name "*.ear" -exec ls -l {} \;
If you need to get total size, here is a script proposal
#!/bin/bash
totalSize=0
allSizes=`find . -type f -name *.ear -exec stat -c "%s" {} \;`
for fileSize in $allSizes; do
totalSize=`echo "$(($totalSize+$fileSize))"`
done
echo "Total size is $totalSize bytes"
You could try for loop:
for i in `find . -iname "*.ear"`; do ls -lh $i; done

Resources