fd: Thoughts on non-zero exit code for no matches?
grep returns a non-zero exit code when no matches are found, making it easy to include in shell scripts and if conditions directly without having to shell out to test to analyze the results.
What are your thoughts on having fd do the same so that fd not-exists and fd exists have differing exit codes that could be directly checked?
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 5
- Comments: 26 (15 by maintainers)
Thanks, everyone!
I think I’m now leaning towards using
-q/--quietwith an additional hidden alias (either--has-resultsor--has-match, no real preference here).Any final objections? Preferences for either “has-results” or “has-match”?
Ok, let’s try to implement this. I like
--test. We can probably reuse the--max-resultsfunctionality and run a--max-results=1search. Instead of printing anything to the console, we would simply return 0 or 1, depending on whether we have at least one result or not.What do you think @ChrisPenner @mqudsi @vn971?
In particular, the decision not to print anything? Otherwise, we would have to use
> /dev/nullin scripts. And we already havefd -1 patternto print the first search result and quit.Thank you for the feedback!
Interesting thought. However, I’m not sure that it’s a good idea to implement it this way.
findalways returns 0 if it finished the search without any errors, even if there are no results.The idea is that you can use the exit code to tell whether or not you can rely on the search results. If the exit code is non-zero, there might be folders/files which were not searched (due to permission issues, for example). I believe we should probably do the same with
fd(we currently silently ignore these).Coming back to your use case, I agree that it would be nice to use
fdthis way in shell scripts, but I guess there are some rather simple workarounds that would achieve the same, for exampleJust chiming in that I’d also appreciate a flag for setting exit status 😃
Sure, the given alternatives work; but I’d need to add a comment to have any faith that anyone would understand why. If I saw something like
fd something | head -c 1 | grep . 1>/dev/nullI’d have no clue what the intent was; whereas if I saw:Then the intent is clear and my coworkers won’t get confused 😄
Alternative names for the option could be
--testor--matchSure thing!
My argument for
-qand why I think it works despite what the responses to that were before is that even if it changes the behavior offd(i.e. it exits after the first match), the observable (non-error) behavior of fd does not change. Iffd -qreturns after one result or after one thousand, the user-observable state (output + status code) does not change - only how quickly that result is rendered changes. The user can’t know how long the result should take (caches, ignored directories, etc) and in all cases, even if they can expect “slow” or “fast” depending on the number of results, it’s a non-deterministic factor. That’s all to say if you agree with-qexcept you feel that it shouldn’t change the behavior offd, then my counter is that it doesn’t change the user observable behavior, only the internal logic, which is within its right.It’s unfortunate that the status code depends on whether or not
-qis specified (instead of always terminating with a non-zero status code if no results were found, a lagrepand co and just documenting that as a breaking change), but I think that documenting the exit code change with-qis still preferable to--has-fooor whatever because it doesn’t break with unix convention and is more discoverable. I know you mentionedfinddoesn’t change its exit code - to me that is bizarre because I would have intuitively expectedfindto behave likegrep(I mean, it’s literally an imperative command “sudo, find these files!” so if it doesn’t have any results to return, you’d expect it to let you know). In all cases,fdisn’t by any means a rewrite offind(it doesn’t support the same parameters) so I think it’s not the end of the world to break with in this regard as well, but as I mentioned before, I’m not going to pick this hill to die on.fwiw, this is the rationale we use in https://github.com/fish-shell/fish-shell for using
-qto abort on first match for all our first-party builtins and functions and it’s the behavior that pretty much all the other (maintained) shells and greybeard utilities are using.(this is all aside from
fd -qjust being plain shorter and easier to work with and there generally being no question of whether or not-qshould be a shortcode for--quiet)Really? I would expect a
--quietoption to do exactly the same, but without the output. The option that is being proposed here would change the behavior (only search for the first result, then quit).that’s true, but it would be used to test if a search has a match. Another possibility would be
--checkor--has-match ….I argued above that we don’t want to do this because it would not reflect what
finddoes.finddoes return 0 if there are no matches (and no filesystem errors have occurred). We don’t necessarily have to be consistent withfind, but in this case, I think we should aim to be.In the meantime (since writing the comments above) there have been some new developments:
We now have a
--max-results=<count>option and a-1alias for--max-results=1that can be used to exit early after finding the first result(s). This is even faster than the early exit viafd … | head -n1because the latter is actually running until the second result.Ok, agreed. But I would assume that this use case (testing for existence of search results) is something that usually comes up in a script, not in the interactive use of a terminal. Therefore, I don’t think it’s too bad if there is no super-short way to achieve that result is found.
As you said, I think that’s negligible compared to the IO overhead (accessing the disk / cache) to get the search results.
Fair point. I think there are slightly more readable alternatives though:
Ok. Let’s reopen this ticket and see what others think.
Fair enough.
It does occur to me that a better option here (if one were to want to improve this) might be to add a
--has-resultsor similar flag that would use the 0/1 return code, which has the added benefit of allowingfdto terminate early when a match is found.