2018-01-26 15:36:46 +03:00
# fselect
Find files with SQL-like queries
2018-03-01 12:51:57 +03:00
[![Crates.io ](https://img.shields.io/crates/v/fselect.svg )](https://crates.io/crates/fselect)
2022-01-15 11:02:20 +03:00
[![build ](https://github.com/jhspetersson/fselect/actions/workflows/rust.yml/badge.svg )](https://github.com/jhspetersson/fselect/actions/workflows/rust.yml)
2018-02-26 16:13:42 +03:00
2018-02-02 00:17:52 +03:00
### Why use fselect?
While it doesn't tend to fully replace traditional `find` and `ls` , **fselect** has these nice features:
* SQL-like (not real SQL, but highly relaxed!) grammar easily understandable by humans
2018-10-30 13:20:21 +03:00
* complex queries
2020-10-13 11:21:59 +03:00
* aggregate, statistics, date, and other functions
2018-02-19 17:55:52 +03:00
* search within archives
2020-04-22 11:31:21 +03:00
* `.gitignore` , `.hgignore` , and `.dockerignore` support (experimental)
2019-07-14 10:59:13 +03:00
* search by width and height of images, EXIF metadata
2018-03-07 10:03:33 +03:00
* search by MP3 info
2019-03-08 16:24:48 +03:00
* search by extended file attributes
* search by file hashes
2019-05-14 09:52:47 +03:00
* search by MIME type
2018-02-02 00:17:52 +03:00
* shortcuts to common file types
2020-06-05 10:44:05 +03:00
* interactive mode
2018-03-01 14:38:41 +03:00
* various output formatting (CSV, JSON, and others)
2018-02-02 00:17:52 +03:00
More is under way!
2018-01-29 12:23:59 +03:00
### Installation
2019-07-20 00:29:25 +03:00
#### Latest release from source
2018-03-11 00:35:31 +03:00
2018-01-29 12:24:22 +03:00
* Install [Rust with Cargo ](https://www.rust-lang.org/en-US/install.html ) and its dependencies to build a binary
2018-01-29 12:23:59 +03:00
* Run `cargo install fselect`
2018-01-29 12:24:59 +03:00
2018-03-11 00:35:31 +03:00
#### Arch Linux
[AUR package ](https://aur.archlinux.org/packages/fselect/ ), thanks to [@asm0dey ](https://github.com/asm0dey )
2019-11-11 13:52:05 +03:00
#### NixOS
[`fselect` in `nixpkgs` ](https://github.com/filalex77/nixpkgs/blob/1eced92263395896c10cea69e5f60e8be5f43aeb/pkgs/tools/misc/fselect/default.nix ), thanks to [@filalex77 ](https://github.com/filalex77 )
2018-08-12 16:53:00 +03:00
#### Other Linux
2024-05-03 10:34:55 +03:00
[Static build with musl ](https://github.com/jhspetersson/fselect/releases/download/0.8.6/fselect-x86_64-linux-musl.gz ).
2018-08-12 16:53:00 +03:00
2018-03-11 00:35:31 +03:00
#### Windows 64bit
2024-05-03 10:34:55 +03:00
A statically precompiled [binary ](https://github.com/jhspetersson/fselect/releases/download/0.8.6/fselect-x86_64-win.zip ) is available at Github downloads.
2018-01-29 12:23:59 +03:00
2023-06-02 08:42:43 +03:00
#### Windows via winget
* Install [winget ](https://github.com/microsoft/winget-cli )
* Run `winget install -e --id fselect.fselect`
2021-11-14 22:29:45 +03:00
#### Windows via Chocolatey
2019-07-19 11:47:31 +03:00
* Install [Chocolatey ](https://chocolatey.org/install )
* Run `choco install fselect`
2022-05-14 19:34:37 +03:00
#### Windows via Scoop
2021-11-14 22:29:45 +03:00
* Install [Scoop ](https://scoop.sh )
* Run `scoop install fselect`
2021-04-07 14:38:33 +03:00
#### Mac via Homebrew
2018-03-13 11:20:23 +03:00
2019-09-29 11:30:25 +03:00
* Install [brew ](https://brew.sh )
2018-03-13 11:20:23 +03:00
* Run `brew install fselect`
2021-04-07 14:38:33 +03:00
#### Mac via MacPorts
* Install [MacPorts ](https://www.macports.org )
* Run:
```
sudo port selfupdate
sudo port install fselect
```
2018-02-08 10:18:11 +03:00
### Usage
2023-04-07 18:15:21 +03:00
fselect [ARGS] COLUMN[, COLUMN...] [from ROOT[, ROOT...]] [where EXPR] [group by COLUMNS] [order by COLUMNS] [limit N] [into FORMAT]
2018-02-08 10:18:11 +03:00
2020-06-05 10:44:05 +03:00
### Interactive mode
fselect -i
2018-03-01 19:16:22 +03:00
### Documentation
2019-07-14 10:59:13 +03:00
[More detailed description. Look at examples first. ](docs/usage.md )
2018-03-01 19:16:22 +03:00
2018-01-26 15:36:46 +03:00
### Examples
2018-02-03 21:23:52 +03:00
Find temporary or config files (full path and size):
2018-01-26 15:36:46 +03:00
2018-02-26 15:46:39 +03:00
fselect size, path from /home/user where name = '*.cfg' or name = '*.tmp'
2018-02-26 15:54:57 +03:00
Windows users may omit the quotes:
fselect size, path from C:\Users\user where name = *.cfg or name = * .tmp
Or put all the arguments into the quotes like this:
fselect "name from /home/user/tmp where size > 0"
2018-01-26 15:36:46 +03:00
2024-05-28 18:36:54 +03:00
Search within a directory name with spaces (backticks are also supported):
2018-01-26 15:36:46 +03:00
2024-05-28 18:36:54 +03:00
fselect "name from '/home/user/dir with spaces' where size > 0"
fselect "name from `/home/user/dir with spaces` where size > 0"
Or simply escape the single quotes:
fselect name from \'/home/user/dir with spaces\' where size gt 0
2018-01-26 15:36:46 +03:00
2018-12-12 21:25:26 +03:00
Specify file size, get absolute path, and add it to the results:
2018-01-30 22:31:38 +03:00
2018-12-12 21:25:26 +03:00
cd /home/user
fselect size, abspath from ./tmp where size gt 2g
fselect fsize, abspath from ./tmp where size = 5m
fselect hsize, abspath from ./tmp where size lt 8k
2023-12-01 11:28:42 +03:00
fselect name, size from ./tmp where size between 5mb and 6mb
2018-01-30 22:31:38 +03:00
2018-01-26 15:36:46 +03:00
More complex query:
2018-03-07 11:03:41 +03:00
fselect "name from /tmp where (name = *.tmp and size = 0) or (name = * .cfg and size > 1000000)"
2018-01-26 15:36:46 +03:00
2022-01-17 13:04:25 +03:00
Aggregate functions (you can use curly braces if you want, and even combine them with the regular parentheses):
2018-10-30 13:20:21 +03:00
2022-01-17 13:04:25 +03:00
fselect "MIN(size), MAX{size}, AVG(size), SUM{size}, COUNT(*) from /home/user/Downloads"
2018-10-30 13:20:21 +03:00
Formatting functions:
2018-10-30 23:48:10 +03:00
fselect "LOWER(name), UPPER(name), LENGTH(name), YEAR(modified) from /home/user/Downloads"
2018-10-30 13:20:21 +03:00
2019-09-29 10:16:07 +03:00
Get the year of an oldest file:
fselect "MIN(YEAR(modified)) from /home/user"
2018-01-26 15:36:46 +03:00
Use single quotes if you need to address files with spaces:
2019-02-08 22:29:00 +03:00
fselect "path from '/home/user/Misc stuff' where name != 'Some file'"
2018-01-27 13:31:22 +03:00
2019-01-06 22:23:32 +03:00
Regular expressions of [Rust flavor ](https://docs.rs/regex/1.1.0/regex/#syntax ) are supported:
2018-01-27 13:31:22 +03:00
2018-03-04 14:58:36 +03:00
fselect name from /home/user where path =~ '.*Rust.*'
2018-01-27 13:31:22 +03:00
2019-03-06 10:28:09 +03:00
Negate regular expressions:
fselect "name from . where path !=~ '^\./config'"
Simple globs expand automatically and work with `=` and `!=` operators:
2018-01-27 13:31:22 +03:00
2018-02-26 15:46:39 +03:00
fselect name from /home/user where path = '*Rust*'
2018-01-29 01:14:26 +03:00
2018-03-04 14:46:53 +03:00
Classic LIKE:
2019-02-08 22:29:00 +03:00
fselect "path from /home/user where name like '%report-2018-__-__???'"
2018-03-04 14:46:53 +03:00
2018-02-24 09:15:13 +03:00
Exact match operators to search with regexps disabled:
2019-02-08 22:29:00 +03:00
fselect "path from /home/user where name === 'some_*_weird_*_name'"
2018-02-24 09:15:13 +03:00
2018-03-19 17:40:05 +03:00
Find files by date:
2018-01-29 01:14:26 +03:00
fselect path from /home/user where created = 2017-05-01
2018-03-19 17:40:05 +03:00
fselect path from /home/user where modified = today
fselect path from /home/user where accessed = yesterday
2019-02-08 22:29:00 +03:00
fselect "path from /home/user where modified = 'apr 1'"
fselect "path from /home/user where modified = 'last fri'"
2018-01-29 01:14:26 +03:00
2018-06-08 13:45:42 +03:00
Be more specific to match all files created at interval between 3PM and 4PM:
2018-01-29 01:14:26 +03:00
fselect path from /home/user where created = '2017-05-01 15'
And even more specific:
fselect path from /home/user where created = '2017-05-01 15:10'
fselect path from /home/user where created = '2017-05-01 15:10:30'
Date and time intervals possible (find everything updated since May 1st):
2018-01-30 10:10:06 +03:00
fselect path from /home/user where modified gte 2017-05-01
Default is current directory:
2018-02-26 15:46:39 +03:00
fselect path, size where name = '*.jpg'
2018-01-30 10:10:06 +03:00
Search within multiple locations:
2018-02-26 15:46:39 +03:00
fselect path from /home/user/oldstuff, /home/user/newstuff where name = '*.jpg'
2018-01-30 10:10:06 +03:00
2018-11-03 14:43:54 +03:00
With minimum and/or maximum depth specified (`depth` is a synonym for `maxdepth` ):
2018-01-30 10:10:06 +03:00
2018-02-26 15:46:39 +03:00
fselect path from /home/user/oldstuff depth 5 where name = '*.jpg'
2018-11-03 14:43:54 +03:00
fselect path from /home/user/oldstuff mindepth 2 maxdepth 5, /home/user/newstuff depth 10 where name = '*.jpg'
2018-02-28 18:05:32 +03:00
Optionally follow symlinks:
fselect path, size from /home/user symlinks where name = '*.jpg'
2018-02-01 19:33:33 +03:00
2018-02-19 17:55:52 +03:00
Search within archives (currently only zip-archives are supported):
2018-02-26 15:46:39 +03:00
fselect path, size from /home/user archives where name = '*.jpg'
2018-02-19 17:55:52 +03:00
Or in combination:
2018-07-09 17:34:30 +03:00
fselect size, path from /home/user depth 5 archives symlinks where name = '*.jpg' limit 100
2019-02-18 17:38:49 +03:00
Enable `.gitignore` or `.hgignore` support:
2018-07-09 17:34:30 +03:00
2019-02-18 17:38:49 +03:00
fselect size, path from /home/user/projects gitignore where name = '*.cpp'
fselect size, path from /home/user/projects hgignore where name = '*.py'
2018-02-19 17:55:52 +03:00
2018-02-22 18:24:30 +03:00
Search by image dimensions:
2019-12-21 13:06:32 +03:00
fselect CONCAT(width, 'x', height), path from /home/user/photos where width gte 2000 or height gte 2000
2018-02-22 18:24:30 +03:00
2019-03-08 15:47:42 +03:00
Find square images:
fselect path from /home/user/Photos where width = height
2022-04-14 13:24:56 +03:00
Find images with a known name part but unknown extension:
2019-03-08 15:47:42 +03:00
2022-04-14 13:24:56 +03:00
fselect path from /home/user/projects where name = "*RDS*" and width gte 1
2018-03-07 10:03:33 +03:00
Find old-school rap MP3 files:
2019-05-22 16:16:01 +03:00
fselect duration, path from /home/user/music where genre = Rap and bitrate = 320 and mp3_year lt 2000
2018-03-07 10:03:33 +03:00
2018-02-02 10:53:46 +03:00
Shortcuts to common file extensions:
2018-02-01 19:33:33 +03:00
fselect path from /home/user where is_archive = true
2019-05-14 09:52:47 +03:00
fselect path, mime from /home/user where is_audio = 1
fselect path, mime from /home/user where is_book != false
2021-11-19 17:33:41 +03:00
Even simpler way of using boolean columns:
fselect path from /home/user where is_doc
fselect path from /home/user where is_image
fselect path from /home/user where is_video
2018-02-05 18:29:24 +03:00
Find files with dangerous permissions:
2021-11-19 17:33:41 +03:00
fselect mode, path from /home/user where other_write or other_exec
fselect mode, path from /home/user where other_all
2018-02-05 18:29:24 +03:00
Simple glob-like expressions or even regular expressions on file mode are possible:
2018-02-26 15:46:39 +03:00
fselect mode, path from /home/user where mode = '*rwx'
2018-03-01 10:20:04 +03:00
fselect mode, path from /home/user where mode =~ '.*rwx$'
2018-02-06 15:09:25 +03:00
Find files by owner's uid or gid:
2018-02-26 15:27:38 +03:00
fselect uid, gid, path from /home/user where uid != 1000 or gid != 1000
2018-02-06 17:59:18 +03:00
Or by owner's or group's name:
2018-02-26 15:27:38 +03:00
fselect user, group, path from /home/user where user = mike or group = mike
2018-04-04 15:50:57 +03:00
Find special files:
2021-11-19 17:33:41 +03:00
fselect name from /usr/bin where suid
fselect path from /tmp where is_pipe
fselect path from /tmp where is_socket
2018-08-12 14:53:06 +03:00
2019-02-10 12:13:15 +03:00
Find files with xattrs, check if particular xattr exists, or get its value:
2019-02-10 12:53:11 +03:00
fselect "path, has_xattrs, has_xattr(user.test), xattr(user.test) from /home/user"
2019-02-10 12:13:15 +03:00
2018-08-12 14:53:06 +03:00
Include arbitrary text as columns:
2019-02-08 22:29:00 +03:00
fselect "name, ' has size of ', size, ' bytes'"
2018-06-01 09:23:47 +03:00
2023-04-07 18:15:21 +03:00
Group results:
fselect "ext, count(*) from /tmp group by ext"
2018-06-01 09:23:47 +03:00
Order results:
fselect path from /tmp order by size desc, name
fselect modified, fsize, path from ~ order by 1 desc, 3
2018-02-08 10:14:42 +03:00
Finally limit the results:
fselect name from /home/user/samples limit 5
2018-03-01 14:30:29 +03:00
Format output:
fselect size, path from /home/user limit 5 into json
fselect size, path from /home/user limit 5 into csv
2019-01-05 11:21:15 +03:00
fselect size, path from /home/user limit 5 into html
2018-01-27 13:31:22 +03:00
2018-01-29 12:23:59 +03:00
### License
MIT/Apache-2.0
2019-07-21 01:02:13 +03:00
---
2022-05-18 12:02:39 +03:00
Supported by [JetBrains IDEA ](https://jb.gg/OpenSourceSupport ) open source license