0

I've got a file hidden somewhere, it's either named file.foo.bar.txt or file.bar.foo.txt, but I'm not sure which it is.

Right now, I'm just running find file*foo*txt because I know the file will be in the list, but I have to sort through the list to find the actual file.

Mostly out of curiosity (the list is short and realistically I can find the file), is there a way to find file.(foo&bar).txt such that the file will be found, regardless of which is the actual file?

2 Answers 2

1

The command find file*foo*txt doesn't really use find.

It's your shell who expands file*foo*txt before find even runs. Then find gets possibly many arguments as its starting points; and no tests, no actions. The default action of -print is assumed.

This is like printf '%s\n' file*foo*txt. Both printf and your find only print what the shell supplies; except if there is no match. Or except if the shell returns a directory name (possibly among other names); in such case printf will just print it, while find will print it plus paths to every file in the directory, recursively.

Your task can be done with find (not the shell) actually performing some matching. Use several -name tests. The default behavior is to join tests with -a (logical AND). This fits cases where you want the filename to match several patterns at once.

find . -type f -name 'file.*' -name '*.txt' -name '*.foo.*' -name '*.bar.*'

Notes:

  • These patterns are not regular expressions. * here is a wildcard but . is literal. I used . because you wrote "file.foo.bar.txt or file.bar.foo.txt".
  • find is recursive. Use -maxdepth 1 or (if your find doesn't support it) read this: Limit POSIX find to specific depth.
  • Note the patterns are quoted. This is to protect them from being expanded by the shell (compare this question).

If you want literally file.foo.bar.txt or file.bar.foo.txt then use -o (logical OR):

find . -type f \( -name file.foo.bar.txt -o -name file.bar.foo.txt \)

Note you often need parentheses with -o. Without them -type f -name … -o -name … would not do what we want.

And there is -regex. It's a match on the whole path and there are several flavors.

0

The default operation in find is and, so for a loose match you can just use

find .  -name 'file*foo*txt' -name 'file*bar*txt'

but for a rigid match you can resort to a regular expression:

find . -regextype posix-extended -regex '.*/file\.(foo\.bar|bar\.foo)\.txt'

You need to remember the regex has to match the full path, hence the .*/ at the beginning.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .