12

Given a nested directory, I would like to list all tif files with extension .tif, .TIF, .tiff, .TIFF.

Currently I'm using

find . -type f -iname *.TIF -print ; find . -type f -iname *.TIFF -print;

Using -iname allows me to be case-insensitive but it goes through the directory twice to get files with .tif and .tiff. Is there a better way to do this? Perhaps with brace expansion?

Why not *.tif*?

In some cases, my directories might have auxiliary files with extension .tif.aux.xml alongside the tiffs. I'd like to ignore those.

6
  • Make an alias with it in your source file for the command, such as "findtif" or something. Jul 5, 2021 at 21:14
  • 1
    why not do ren *.tiff *.tif first ? :-) (hint: don't)
    – Jeffrey
    Jul 5, 2021 at 22:26
  • @Jeffrey While I don't want to modify the data in question, I'm curious as to why this is discouraged. I mean aside from the fact that it won't fix the auxiliary file problem. Jul 6, 2021 at 6:19
  • Do you really need find? If you're using zsh (which supports recursive ** in a glob) for instance, echo **/*.{tif,tiff,TIF,TIFF} should be enough. Jul 6, 2021 at 16:19
  • @vikarjramun The OP's question is marked "bash," although bash does support this. However, this solution does not limit the search results to only include regular files, nor does it allow a lot of the other features that find has (which OP may need; not sure). Jul 7, 2021 at 19:37

3 Answers 3

35

find supports an “or” disjunction, -o:

find . -type f \( -iname \*.tif -o -iname \*.tiff \)

This will list all files whose name matches *.tif or *.tiff, ignoring case.

-print is the default action so it doesn’t need to be specified here. *, (, and ) are escaped so that they lose their significance for the shell.

3
  • Instead of grouping you can give an action to each pattern instead, e.g. find . -iname \*.tif -print -o -iname \*.tiff -print. This is useful when you want to skip traversing some directories when searching, e.g. find . -name .git -prune -o -name node_modules -prune -o -iname \*.tif -print -o -iname \*.tiff -print.
    – hlovdal
    Jul 6, 2021 at 23:45
  • @hlovdal there’s no need to specify an action when the action is always -print, so find . -iname \*.tif -o -iname \*.tiff; but you dropped the -type f. In your second example the actions are different, and I’m not sure it’s better than find . \( -name .git -o -name node_modules \) -prune -o -type f \( -iname \*.tif -o -iname \*.tiff \) -print — I guess it’s a question of habit. Jul 8, 2021 at 14:03
  • Unless I run a find command purely for screen output (which is not that often) I actually always use -print0.
    – hlovdal
    Jul 8, 2021 at 23:18
33

Shorter than using -o, use a regular expression instead

find . -type f -iregex '.*\.tiff?'

Brace expansion is not part of glob matching, so cannot be used with -(i)name.

7
  • 2
    Explain the regex, please.
    – Scottie H
    Jul 6, 2021 at 16:49
  • 1
    @ScottieH it matches everything ending with .tif or .tiff
    – loa_in_
    Jul 6, 2021 at 17:05
  • 7
    It is always better to err on the side of caution with these things. The pattern matches .tif followed by one or zero f characters. ?makes the previous character optional. Not trying to show off here, just trying to show how small the effort is. noi. :-)
    – Björn
    Jul 6, 2021 at 19:55
  • 2
    @ScottieH it matches names ending .tif with an optional final f
    – OrangeDog
    Jul 6, 2021 at 20:18
  • 2
    This is slower than the -o version, by not quite 50% in my tests, although that is probably not significant in most scenarios ;-) — certainly not compared to the I/O time on many systems if the directories aren’t already cached. Jul 7, 2021 at 21:12
-2

Here is a simple hack to get your desired output assuming you are in the top-level directory of the tree where you want to run the find command. Disclaimer: It will not fit advanced usage or find scenarios:

find -type f |egrep '.tif$|.tiff$|.TIF$|.TIFF$'

Explanation:

  1. By default, gnu find recurses into the current directory and prints the output to stdout (no need of a dot or -print option).
  2. The egrep allows extended regular expressions. The $ at the end means that the filename has to end in, example, tif. Hence, foo.tif.bar will not be considered as a match.
  3. The pipes are an OR to match any of the patterns.
3
  • Given that GNU find includes a lot of non-standard features and there are plenty of systems which do not use GNU utilities, I would err on the side of caution and avoid extensions which are easily avoided (such as not specifying .). This is also a much less efficient solution than Stephen's. Jul 7, 2021 at 19:40
  • this will fail if there are any files whose names contain newlines. And it also fails to find files with mixed cases like .Tif, .tiFF...
    – phuclv
    Jul 8, 2021 at 7:33
  • @phulcv Correct. However, this was not part of the question, There was no need to downvote :) Will, I added a disclaimer that it would work only for simple cases (he is a newbie and I was trying to avoid advanced usage). Jul 9, 2021 at 1:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.