]> Sergey Matveev's repositories - bfs.git/blob - README.md
Skip mtab
[bfs.git] / README.md
1 <div align="center">
2
3 # `bfs`
4
5 <a href="https://github.com/tavianator/bfs/releases"><img src="https://img.shields.io/github/v/tag/tavianator/bfs?label=version" alt="Version" align="left"></a>
6 <a href="/LICENSE"><img src="https://img.shields.io/badge/license-0BSD-blue.svg" alt="License" align="left"></a>
7 <a href="https://github.com/tavianator/bfs/actions/workflows/ci.yml"><img src="https://github.com/tavianator/bfs/actions/workflows/ci.yml/badge.svg" alt="CI Status" align="right"></a>
8 <a href="https://codecov.io/gh/tavianator/bfs"><img src="https://img.shields.io/codecov/c/github/tavianator/bfs?token=PpBVuozOVC" alt="Code coverage" align="right"/></a>
9 <br clear="all">
10
11 **[Features]   •   [Installation]   •   [Usage]   •   [Building]   •   [Hacking]   •   [Changelog]**
12
13 [Features]: #features
14 [Installation]: #installation
15 [Usage]: /docs/USAGE.md
16 [Building]: /docs/BUILDING.md
17 [Hacking]: /docs/HACKING.md
18 [Changelog]: /docs/CHANGELOG.md
19
20 <picture>
21   <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tavianator/bfs/gh-pages/animation-dark.svg">
22   <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/tavianator/bfs/gh-pages/animation-light.svg">
23   <img alt="Screencast" src="https://raw.githubusercontent.com/tavianator/bfs/gh-pages/animation-light.svg">
24 </picture>
25 <p></p>
26
27 </div>
28
29 `bfs` is a variant of the UNIX `find` command that operates [**breadth-first**](https://en.wikipedia.org/wiki/Breadth-first_search) rather than [**depth-first**](https://en.wikipedia.org/wiki/Depth-first_search).
30 It is otherwise compatible with many versions of `find`, including
31
32 <div align="center">
33
34 **[POSIX]   •   [GNU]   •   [FreeBSD]   •   [OpenBSD]   •   [NetBSD]   •   [macOS]**
35
36 [POSIX]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html
37 [GNU]: https://www.gnu.org/software/findutils/
38 [FreeBSD]: https://www.freebsd.org/cgi/man.cgi?find(1)
39 [OpenBSD]: https://man.openbsd.org/find.1
40 [NetBSD]: https://man.netbsd.org/find.1
41 [macOS]: https://ss64.com/osx/find.html
42
43 </div>
44
45 If you're not familiar with `find`, the [GNU find manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) provides a good introduction.
46
47
48 Features
49 --------
50
51 <details>
52 <summary>
53 <code>bfs</code> operates breadth-first, which typically finds the file(s) you're looking for faster.
54 </summary>
55 <p></p>
56
57 Imagine the following directory tree:
58
59 <pre>
60 haystack
61 ├── deep
62 │   └── 1
63 │       └── 2
64 │           └── 3
65 │               └── 4
66 │                   └── ...
67 └── shallow
68     └── <strong>needle</strong>
69 </pre>
70
71 `find` will explore the entire `deep` directory tree before it ever gets to the `shallow` one that contains what you're looking for.
72 On the other hand, `bfs` lists files from shallowest to deepest, so you never have to wait for it to explore an entire unrelated subtree.
73
74 <table>
75 <tbody>
76 <tr><th><code>bfs</code></th><th><code>find</code></th></tr>
77 <tr>
78 <td width="506" valign="top">
79
80 ```console
81 $ bfs haystack
82 haystack
83 haystack/deep
84 haystack/shallow
85 haystack/deep/1
86 haystack/shallow/needle
87 ...
88 ```
89
90 </td>
91 <td width="506" valign="top">
92
93 ```console
94 $ find haystack
95 haystack
96 haystack/deep
97 haystack/deep/1
98 haystack/deep/1/2
99 haystack/deep/1/2/3
100 haystack/deep/1/2/3/4
101 ...
102 haystack/shallow
103 haystack/shallow/needle
104 ```
105
106 </td>
107 </tr>
108 </tbody>
109 </table>
110 </details>
111
112 <details>
113 <summary>
114 <code>bfs</code> tries to be easier to use than <code>find</code>, while remaining compatible.
115 </summary>
116 <p></p>
117
118 For example, `bfs` is less picky about where you put its arguments:
119
120 <table>
121 <tbody>
122 <tr><th><code>bfs</code></th><th><code>find</code></th></tr>
123 <tr>
124 <td width="506">
125
126 ```console
127 $ bfs -L -name 'needle' haystack
128 haystack/needle
129
130 $ bfs haystack -L -name 'needle'
131 haystack/needle
132
133 $ bfs -L haystack -name 'needle'
134 haystack/needle
135 ```
136
137 </td>
138 <td width="506">
139
140 ```console
141 $ find -L -name 'needle' haystack
142 find: paths must precede expression: haystack
143
144 $ find haystack -L -name 'needle'
145 find: unknown predicate `-L'
146
147 $ find -L haystack -name 'needle'
148 haystack/needle
149 ```
150
151 </td>
152 </tr>
153 </tbody>
154 </table>
155 </details>
156
157 <details>
158 <summary>
159 <code>bfs</code> gives helpful errors and warnings.
160 </summary>
161 <p></p>
162
163 For example, `bfs` will detect and suggest corrections for typos:
164
165 ```console
166 $ bfs -nam needle
167 bfs: error: bfs -nam needle
168 bfs: error:     ~~~~
169 bfs: error: Unknown argument; did you mean -name?
170 ```
171
172 `bfs` also includes a powerful static analysis to help catch mistakes:
173
174 ```console
175 $ bfs -print -name 'needle'
176 bfs: warning: bfs -print -name needle
177 bfs: warning:            ~~~~~~~~~~~~
178 bfs: warning: The result of this expression is ignored.
179 ```
180
181 </details>
182
183 <details>
184 <summary>
185 <code>bfs</code> adds some options that make common tasks easier.
186 </summary>
187 <p></p>
188
189 For example, the `-exclude` operator skips over entire subtrees whenever an expression matches.
190 `-exclude` is both more powerful and easier to use than the standard `-prune` action; compare
191
192 <pre>
193 $ bfs -name config <strong>-exclude -name .git</strong>
194 </pre>
195
196 to the equivalent
197
198 <pre>
199 $ find <strong>! \( -name .git -prune \)</strong> -name config
200 </pre>
201
202 As an additional shorthand, `-nohidden` skips over all hidden files and directories.
203 See the [usage documentation](/docs/USAGE.md#extensions) for more about the extensions provided by `bfs`.
204 </details>
205
206
207 Installation
208 ------------
209
210 <details open>
211 <summary>
212 <code>bfs</code> may already be packaged for your operating system.
213 </summary>
214 <p></p>
215
216 <table>
217 <tbody>
218 <tr><th>Linux</th><th>macOS</th></tr>
219
220 <tr>
221 <td width="506" valign="top" rowspan="3">
222
223 <pre>
224 <strong><a href="https://pkgs.alpinelinux.org/packages?name=bfs">Alpine Linux</a></strong>
225 # apk add bfs
226
227 <strong><a href="https://archlinux.org/packages/extra/x86_64/bfs/">Arch Linux</a></strong>
228 # pacman -S bfs
229
230 <strong><a href="https://packages.debian.org/sid/bfs">Debian</a>/<a href="https://packages.ubuntu.com/kinetic/bfs">Ubuntu</a></strong>
231 # apt install bfs
232
233 <strong><a href="https://src.fedoraproject.org/rpms/bfs">Fedora Linux</a></strong>
234 # dnf install bfs
235
236 <strong><a href="https://packages.guix.gnu.org/packages/bfs/">GNU Guix</a></strong>
237 # guix install bfs
238
239 <strong><a href="https://search.nixos.org/packages?channel=unstable&show=bfs&from=0&size=1&sort=relevance&type=packages&query=bfs">NixOS</a></strong>
240 # nix-env -i bfs
241
242 <strong><a href="https://voidlinux.org/packages/?arch=x86_64&q=bfs">Void Linux</a></strong>
243 # xbps-install -S bfs
244 </pre>
245
246 </td>
247 <td width="506" valign="top">
248
249 <pre>
250 <strong><a href="https://formulae.brew.sh/formula/bfs">Homebrew</a></strong>
251 $ brew install bfs
252
253 <strong><a href="https://ports.macports.org/port/bfs/">MacPorts</a></strong>
254 # port install bfs
255 </pre>
256
257 </td>
258 </tr>
259 <tr><th height="1">BSD</th></tr>
260 <tr>
261 <td width="506" valign="top">
262
263 <pre>
264 <strong><a href="https://www.freshports.org/sysutils/bfs">FreeBSD</a></strong>
265 # pkg install bfs
266
267 <strong><a href="https://openports.pl/path/sysutils/bfs">OpenBSD</a></strong>
268 # pkg_add bfs
269 </pre>
270
271 </td>
272 </tr>
273 </tbody>
274 </table>
275 </details>
276
277 <details>
278 <summary>
279 To build <code>bfs</code> from source, you may need to install some dependencies.
280 </summary>
281 <p></p>
282
283 The only absolute requirements for building `bfs` are a C compiler, [GNU make](https://www.gnu.org/software/make/), and [Bash](https://www.gnu.org/software/bash/).
284 These are installed by default on many systems, and easy to install on most others.
285 Refer to your operating system's documentation on building software.
286
287 `bfs` also depends on some system libraries for some of its features.
288 Here's how to install them on some common platforms:
289
290 <pre>
291 <strong>Alpine Linux</strong>
292 # apk add acl{,-dev} attr{,-dev} libcap{,-dev} liburing-dev oniguruma-dev
293
294 <strong>Arch Linux</strong>
295 # pacman -S acl attr libcap liburing oniguruma
296
297 <strong>Debian/Ubuntu</strong>
298 # apt install acl libacl1-dev attr libattr1-dev libcap2-bin libcap-dev liburing-dev libonig-dev
299
300 <strong>Fedora</strong>
301 # dnf install acl libacl-devel libattr-devel libcap-devel liburing-devel oniguruma-devel
302
303 <strong>NixOS</strong>
304 # nix-env -i acl attr libcap liburing oniguruma
305
306 <strong>Void Linux</strong>
307 # xbps-install -S acl-{devel,progs} attr-{devel,progs} libcap-{devel,progs} liburing-devel oniguruma-devel
308
309 <strong>Homebrew</strong>
310 $ brew install oniguruma
311
312 <strong>MacPorts</strong>
313 # port install oniguruma6
314
315 <strong>FreeBSD</strong>
316 # pkg install oniguruma
317 </pre>
318
319 These dependencies are technically optional, though strongly recommended.
320 See the [build documentation](/docs/BUILDING.md#dependencies) for how to disable them.
321 </details>
322
323 <details>
324 <summary>
325 Once you have the dependencies, you can build <code>bfs</code>.
326 </summary>
327 <p></p>
328
329 Download one of the [releases](https://github.com/tavianator/bfs/releases) or clone the [git repo](https://github.com/tavianator/bfs).
330 Then run
331
332     $ make
333
334 This will build the `./bin/bfs` binary.
335 Run the test suite to make sure it works correctly:
336
337     $ make check
338
339 If you're interested in speed, you may want to build the release version instead:
340
341     $ make release
342
343 Finally, if you want to install it globally, run
344
345     # make install
346
347 </details>