Fd: Logical AND

Created on 4 Mar 2019  ยท  7Comments  ยท  Source: sharkdp/fd

Hello, I have a use case where I have to find files by multiple criteria like directory suffix and a filename.

dir_A/B_file
dir_A/A_file
dir_B/B_file

where I need to find only directories with _A and files B_.
Of course, I can find all B_ prefixed files and use grep to filter directories, but I'm wondering if there is a way to do that in one step.

I tried regexp look around, but got an error error: look-around, including look-ahead and look-behind, is not supported

For some reason, fd | grep '_A.*B_' works as expected while fd '_A.*B_' returns an empty result. I'm wondering if that's because of some optimization.

Is there any syntactic way to chain search criteria?

question

Most helpful comment

As @tavianator said, you need to use --full-path to match on the whole file path (instead of just the basename). So this should work:

fd -p '_A.*B_'

If you want directories that end with _A, you should probably use _A/.*B_. In addition, if you want to make sure that there is no / after B_ (otherwise it would be a directory including B_), you could use _A/.*B_[^/]*$.

Agreed, all of this is not very pretty and it's definitely one of those scenarios where find (or maybe fselect) might actually be more suited to the task. There is currently no way to use two patterns. Other filters are usually AND-ed, though (using a pattern, --type and --extension, for example).

All 7 comments

a less than ideal workaround would be something like: fd _A | grep B_

in my experience, that won't work.

bash-5.0$ cd /tmp
bash-5.0$ mkdir test
bash-5.0$ cd test
bash-5.0$ mkdir dir_{A,B}
bash-5.0$ ls
dir_A  dir_B
bash-5.0$ touch dir_{A,B}/{A,B}_file
bash-5.0$ tree
.
โ”œโ”€โ”€ dir_A
โ”‚ย ย  โ”œโ”€โ”€ A_file
โ”‚ย ย  โ””โ”€โ”€ B_file
โ””โ”€โ”€ dir_B
    โ”œโ”€โ”€ A_file
    โ””โ”€โ”€ B_file

2 directories, 4 files
bash-5.0$ fd _A | grep B_
# nothing
bash-5.0$ fd B_ | grep _A
dir_A/B_file
bash-5.0$

my understanding is that fd has some optimization that stops traversing into subdirectories when it finds the match. It does not match path, it only looks for leaf (filename or directory) names

I think you want -p/--full-path

As @tavianator said, you need to use --full-path to match on the whole file path (instead of just the basename). So this should work:

fd -p '_A.*B_'

If you want directories that end with _A, you should probably use _A/.*B_. In addition, if you want to make sure that there is no / after B_ (otherwise it would be a directory including B_), you could use _A/.*B_[^/]*$.

Agreed, all of this is not very pretty and it's definitely one of those scenarios where find (or maybe fselect) might actually be more suited to the task. There is currently no way to use two patterns. Other filters are usually AND-ed, though (using a pattern, --type and --extension, for example).

my understanding is that fd has some optimization that stops traversing into subdirectories when it finds the match.

There is no such behavior. We could potentially miss search results otherwise. If you search for foo (with --full-path), you will find bar/foo, but also bar/foo/1 and bar/foo/2.

Thanks for detailed explanation. I think this knowledge deserve place is example section of the man page.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sharkdp picture sharkdp  ยท  3Comments

mwgkgk picture mwgkgk  ยท  3Comments

sharkdp picture sharkdp  ยท  4Comments

ChengCat picture ChengCat  ยท  3Comments

mathomp4 picture mathomp4  ยท  3Comments