List all graphic image files with find? [closed] - linux

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 2 years ago.
Improve this question
There are many types of graphic images in this huge archive such as .jpg, .gif, .png, etc. I don't know all the types. Is there a way with 'find' to be able to have it list all the graphic images regardless of their dot extension name? Thanks!

This should do the trick
find . -name '*' -exec file {} \; | grep -o -P '^.+: \w+ image'
example output:
./navigation/doc/Sphärische_Trigonometrie-Dateien/bfc9bd9372f650fd158992cf5948debe.png: PNG image
./navigation/doc/Sphärische_Trigonometrie-Dateien/6564ce3c5b95ded313b84fa918b32776.png: PNG image
./navigation/doc/subr_1.jpe: JPEG image
./navigation/doc/Astroanalytisch-Dateien/Gamma.gif: GIF image
./navigation/doc/Astroanalytisch-Dateien/deltaS.jpg: JPEG image
./navigation/doc/Astroanalytisch-Dateien/GammaBau.jpg: JPEG image

The following suits me better since in my case I wanted to pipe this list of files to another program.
find . -type f -exec file --mime-type {} \+ | awk -F: '{if ($2 ~/image\//) print $1}'
If you wanted to tar the images up (as someone in the comments) asked
find . -type f -exec file --mime-type {} \+ | awk -F: '{if ($2 ~/image\//) printf("%s%c", $1, 0)}' | tar -cvf /tmp/file.tar --null -T -

find . -type f -exec file {} \; | grep -o -P '^.+: \w+ image'
should even be better.

Grepping or using awk for "image" only will not do it. PSD-files will be identified by "Image" with a capital "I" so we need to improve the regexp to either be case insensitive or also include the capital I. EPS-files will not contain the word "image" at all so we need to also match for "EPS" or "Postscript" depending on what you want. So here is my improved version:
find . -type f -exec file {} \; | awk -F: '{ if ($2 ~/[Ii]mage|EPS/) print $1}'

Update (2022-03-03)
This is a refined version with the following changes:
Remove xargs.
Support filenames which contains : based on 林果皞's comment.
find . -type f |
file --mime-type -f - |
grep -F image/ |
rev | cut -d : -f 2- | rev
Below is a more performant solution compared to the chosen answer:
find . -type f -print0 |
xargs -0 file --mime-type |
grep -F 'image/' |
cut -d ':' -f 1
Use -type f instead of -name '*' since the former will search only files while the latter search both files and directories.
xargs execute file with arguments as many as possible, which is super fast compared to find -exec file {} \; which executes file for each found.
grep -F is faster since we only want to match fixed string.
cut is faster than awk (more than 5 times faster as I can recall).

Related to the same problem, I just published a tool called photofind (https://github.com/trimap/photofind). It behaves like the normal find-command but is specialized for image files and supports filtering of results also based on the EXIF-information stored within the image files. See the linked github-repo for more details.

Related

finding files and moving their folders [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 9 years ago.
Improve this question
I have a huge number of text files, organized in a big folder tree, on Debian Linux. What I need is to find all text files having a specific name pattern and then move the containing folder to a destination.
Example:
/home/spenx/src/a12/a1a22.txt
/home/spenx/src/a12/a1a51.txt
/home/spenx/src/a12/a1b61.txt
/home/spenx/src/a12/a1x71.txt
/home/spenx/src/a167/a1a22.txt
/home/spenx/src/a167/a1a51.txt
/home/spenx/src/a167/a1b61.txt
/home/spenx/src/a167/a1x71.txt
The commands:
find /home/spenx/src -name "a1a2*txt"
mv /home/spenx/src/a12 /home/spenx/dst
mv /home/spenx/src/a167 /home/spenx/dst
The result:
/home/spenx/dst/a12/a1a22.txt
/home/spenx/dst/a167/a1a22.txt
Thank you for your help.
SK
combination of find, dirname and mv along with xargs should solve your problem
find /home/spenx/src -name "a1a2*txt" | xargs -n 1 dirname | xargs -I list mv list /home/spenx/dst/
find will fetch list of files
dirname will extract path of file. Note that it can only take one argument at a time
mv will move source directories to destination
xargs is the key to allow output of one command to be passed as arguments to next command
For details of options used with xargs, refer to its man page of just do man xargs on terminal
You can execute:
find /home/spenx/src name "a1a2*txt" -exec mv {} /home/spenx/dst \;
Font: http://www.cyberciti.biz/tips/howto-linux-unix-find-move-all-mp3-file.html
Create this mv.sh script in the current directory that will contain this:
o=$1
d=$(dirname $o)
mkdir /home/spenx/dst/$d 2>/dev/null
mv $o /home/spenx/dst/$d
Make sure it is executable by this command:
chmod +x mv.sh
Next call this command:
find /home/spenx/src -name "a1a2*txt" -exec ./mv.sh {} \;
find /home/spenx/src -name "a1a2*txt" -exec mv "{}" yourdest_folder \;
There's probably multiple ways to do this, but, since it seems you might have multiple matches in a single directory, I would probably do something along this line:
find /home/spenx/src -name "a1a2*txt" -print0 | xargs -0 -n 1 dirname | sort -u |
while read d
do
mv "${d}" /home/spenx/dst
done
It's kind of long, but the steps are:
Find the list of all matching files (the find part), using -print0 to compensate for any names that have spaces or other odd characters in them
extract the directory part of each file name (the xargs ... dirname part)
sort and uniquify the list to get rid of duplicates
Feed the resulting list into a loop that moves each directory in turn

Find in file and then move that file using Linux? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I want to be able to find files that contain certain strings and the move that list of files to directory X
I can use this command to find the files
find . -iname 'commaus*' | xargs grep '>24901<' -sl
and this command to move files
mv * /home/user/scripts/xslt
But is there a way to combine these commands so that the found files are moved.
I have seen similar joined find/action commands such as
find /home/user -name property_images -ok rm -f {} \;
but following this structure is returning an error
find . -iname 'commaus*' | xargs grep '>24901<' -sl -ok mv {} /home/user/scripts/xslt;
Use a loop. In this case, try:
for i in `find . -iname 'commaus*' | xargs grep '>24901<' -sl`; do mv "$i" /home/user/scripts/xslt/; done
Very hackish, but it should work.
you can do this by wrapping it in a for loop
for i in `find /path/to/search -iname 'optionalfilename' -exec grep -H -m1 '>24901<' {} \; | awk -F: '{print $1}'
do
mv $i /path/to/new/location
done
This will not work as expected if filenames contain spaces or colons
Also might be able to try (without loop):
find . -iname 'commaus*' | grep '>24901<' -sl -ok | xargs mv -t /home/user/scripts/xslt

How do I use find to copy and remove extensions keeping the same subdirectory structure [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'm trying to copy all the files from one directory to another, removing all file extensions at the same time.
From directory 0001:
0001/a/1.jpg
0001/b/2.txt
To directory 0002:
0002/a/1
0002/b/2
I've tried several find ... | xargs c...p with no luck.
Recursive copies are really easy to to with tar. In your case:
tar -C 0001 -cf - --transform 's/\(.\+\)\.[^.]\+$/\1/' . |
tar -C 0002 -xf -
If you haven't tar with --transform this can works:
TRG=/target/some/where
SRC=/my/source/dir
cd "$SRC"
find . -type f -name \*.\* -printf "mkdir -p '$TRG/%h' && cp '%p' '$TRG/%p'\n" |\
sed 's:/\.::;s:/./:/:' |\
xargs -I% sh -c "%"
No spaces after the \, need simple end of line, or you can join it to one line like:
find . -type f -name \*.\* -printf "mkdir -p '$TRG/%h' && cp '%p' '$TRG/%p'\n" | sed 's:/\.::;s:/./:/:' | xargs -I% sh -c "%"
Explanation:
the find will find all plain files what have extensions in you SRC (source) directory
the find's printf will prepare the needed shell commands:
command for create the needed directory tree at the TRG (target dir)
command for copying
the sed doing some cosmetic path cleaning, (like correcting /some/path/./other/dir)
the xargs will take the whole line
and execute the prepared commands with shell
But, it will be much better:
simply make an exact copy in 1st step
rename files in 2nd step
easier, cleaner and FASTER (don't need checking/creating the target subdirs)!
Here's some find + bash + install that will do the trick:
for src in `find 0001 -type f` # for all files in 0001...
do
dst=${src/#0001/0002} # match and change beginning of string
dst=${dst%.*} # strip extension
install -D $src $dst # copy to dst, creating directories as necessary
done
This will change the permission mode of all copied files to rwxr-xr-x by default, changeable with install's --mode option.
I came up with this ugly duckling:
find 0001 -type d | sed 's/^0001/0002/g' | xargs mkdir
find 0001 -type f | sed 's/^0001//g' | awk -F '.' '{printf "cp -p 0001%s 0002%s\n", $0, $1}' | sh
The first line creates the directory tree, and the second line copies the files. Problems with this are:
There is only handling for directories and regular files (no
symbolic links etc.)
If there are any periods (besides the
extension) or special characters (spaces, etc.) in the filenames
then the second command won't work.

Find all files with name containing string [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Closed 2 years ago.
Improve this question
I have been searching for a command that will return files from the current directory which contain a string in the filename. I have seen locate and find commands that can find files beginning with something first_word* or ending with something *.jpg.
How can I return a list of files which contain a string in the filename?
For example, if 2012-06-04-touch-multiple-files-in-linux.markdown was a file in the current directory.
How could I return this file and others containing the string touch? Using a command such as find '/touch/'
Use find:
find . -maxdepth 1 -name "*string*" -print
It will find all files in the current directory (delete maxdepth 1 if you want it recursive) containing "string" and will print it on the screen.
If you want to avoid file containing ':', you can type:
find . -maxdepth 1 -name "*string*" ! -name "*:*" -print
If you want to use grep (but I think it's not necessary as far as you don't want to check file content) you can use:
ls | grep touch
But, I repeat, find is a better and cleaner solution for your task.
Use grep as follows:
grep -R "touch" .
-R means recurse. If you would rather not go into the subdirectories, then skip it.
-i means "ignore case". You might find this worth a try as well.
The -maxdepth option should be before the -name option, like below.,
find . -maxdepth 1 -name "string" -print
find $HOME -name "hello.c" -print
This will search the whole $HOME (i.e. /home/username/) system for any files named “hello.c” and display their pathnames:
/Users/user/Downloads/hello.c
/Users/user/hello.c
However, it will not match HELLO.C or HellO.C. To match is case insensitive pass the -iname option as follows:
find $HOME -iname "hello.c" -print
Sample outputs:
/Users/user/Downloads/hello.c
/Users/user/Downloads/Y/Hello.C
/Users/user/Downloads/Z/HELLO.c
/Users/user/hello.c
Pass the -type f option to only search for files:
find /dir/to/search -type f -iname "fooBar.conf.sample" -print
find $HOME -type f -iname "fooBar.conf.sample" -print
The -iname works either on GNU or BSD (including OS X) version find command. If your version of find command does not supports -iname, try the following syntax using grep command:
find $HOME | grep -i "hello.c"
find $HOME -name "*" -print | grep -i "hello.c"
OR try
find $HOME -name '[hH][eE][lL][lL][oO].[cC]' -print
Sample outputs:
/Users/user/Downloads/Z/HELLO.C
/Users/user/Downloads/Z/HEllO.c
/Users/user/Downloads/hello.c
/Users/user/hello.c
If the string is at the beginning of the name, you can do this
$ compgen -f .bash
.bashrc
.bash_profile
.bash_prompt
An alternative to the many solutions already provided is making use of the glob **. When you use bash with the option globstar (shopt -s globstar) or you make use of zsh, you can just use the glob ** for this.
**/bar
does a recursive directory search for files named bar (potentially including the file bar in the current directory). Remark that this cannot be combined with other forms of globbing within the same path segment; in that case, the * operators revert to their usual effect.
Note that there is a subtle difference between zsh and bash here. While bash will traverse soft-links to directories, zsh will not. For this you have to use the glob ***/ in zsh.
find / -exec grep -lR "{test-string}" {} \;
grep -R "somestring" | cut -d ":" -f 1

Linux delete file with size 0 [duplicate]

This question already has answers here:
How to delete many 0 byte files in linux?
(10 answers)
Closed 6 years ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Not suitable for this site This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
How do I delete a certain file in linux if its size is 0. I want to execute this in an crontab without any extra script.
l filename.file | grep 5th-tab | not eq 0 | rm
Something like this?
This will delete all the files in a directory (and below) that are size zero.
find /tmp -size 0 -print -delete
If you just want a particular file;
if [ ! -s /tmp/foo ] ; then
rm /tmp/foo
fi
you would want to use find:
find . -size 0 -delete
To search and delete empty files in the current directory and subdirectories:
find . -type f -empty -delete
-type f is necessary because also directories are marked to be of size zero.
The dot . (current directory) is the starting search directory. If you have GNU find (e.g. not Mac OS), you can omit it in this case:
find -type f -empty -delete
From GNU find documentation:
If no files to search are specified, the current directory (.) is used.
You can use the command find to do this. We can match files with -type f, and match empty files using -size 0. Then we can delete the matches with -delete.
find . -type f -size 0 -delete
On Linux, the stat(1) command is useful when you don't need find(1):
(( $(stat -c %s "$filename") )) || rm "$filename"
The stat command here allows us just to get the file size, that's the -c %s (see the man pages for other formats). I am running the stat program and capturing its output, that's the $( ). This output is seen numerically, that's the outer (( )). If zero is given for the size, that is FALSE, so the second part of the OR is executed. Non-zero (non-empty file) will be TRUE, so the rm will not be executed.
This works for plain BSD so it should be universally compatible with all flavors. Below.e.g in pwd ( . )
find . -size 0 | xargs rm
For a non-recursive delete (using du and awk):
rm `du * | awk '$1 == "0" {print $2}'`
find . -type f -empty -exec rm -f {} \;

Resources