select name, size where name = '*.rs'

Tired of wrestling with find flags? fselect lets you search for files using a familiar SQL-like syntax. It's fast, it's fun, and it actually makes sense.

Get Started View on GitHub

Why fselect?

All the things find can do, but with a query language you'll actually remember tomorrow.

🔍

SQL-like Queries

Write queries that read like English. No more memorizing cryptic flags. select name where size > 1g — done.

📊

Aggregate Functions

COUNT, SUM, AVG, MIN, MAX, STDDEV — get statistics about your files without piping through five different commands.

📦

Search Inside Archives

Look inside ZIP archives as if they were regular directories. Because sometimes the file you need is buried three zips deep.

🎵

MP3 & Media Metadata

Search by bitrate, duration, genre, artist, album. Find that one 320kbps rap track from the 90s in seconds.

🖼

Image & EXIF Data

Filter images by width, height, camera model, GPS coordinates, aperture, ISO — over 40 EXIF fields supported.

🔒

Permissions & ACLs

Check file modes, ownership, SUID bits, extended attributes, POSIX ACLs, and even Linux capabilities.

🔀

Subqueries

Correlated subqueries with IN, NOT IN, EXISTS, NOT EXISTS. Compare files across directories like a boss.

📄

Multiple Output Formats

Tabs, lines, CSV, JSON, HTML — pick whatever your downstream tool or eyeballs prefer.

🛡

Gitignore Support

Respects .gitignore, .hgignore, and .dockerignore so you don't waste time on files you don't care about.

Installation

Pick your poison. fselect is available pretty much everywhere.

Cargo (from source)

$ cargo install fselect

Homebrew (macOS)

$ brew install fselect

MacPorts (macOS)

$ sudo port install fselect

Arch Linux (AUR)

$ yay -S fselect

Debian / Ubuntu

$ dpkg -i fselect_0.10.0-1_amd64.deb

Download .deb

Windows (winget)

> winget install -e --id fselect.fselect

Windows (Chocolatey)

> choco install fselect

Windows (Scoop)

> scoop install fselect

Windows (binary)

Download .zip

Linux (static musl binary)

$ curl -LO https://github.com/jhspetersson/fselect/releases/download/0.10.0/fselect-x86_64-linux-musl.gz
$ gunzip fselect-x86_64-linux-musl.gz
$ chmod +x fselect-x86_64-linux-musl

Download .gz

Usage Examples

From "just find my files" to "give me a statistical breakdown by file type across three directories."

The Basics easy

The general shape of a query. The select keyword is implied — fselect is the select.

fselect [COLUMN, ...] [from PATH] [where CONDITION] [order by COLUMN] [limit N]

Find all JPEG files in your home directory. Dead simple.

$ fselect name from /home/user where name = '*.jpg'

Want to see the size too? Just add another column. Commas between columns are optional, by the way.

$ fselect size path from /home/user where name = '*.cfg' or name = '*.tmp'

No from? It searches the current directory.

$ fselect path, size where name = '*.jpg'

Human-readable file sizes with fsize (or hsize):

$ fselect fsize, path from /home/user where size gt 2g
$ fselect hsize, path from /home/user where size lt 8k

Size ranges with between:

$ fselect name, size from ./tmp where size between 5mb and 6mb

Filtering & Dates easy

Find files by modification date. Supports natural language — today, yesterday, last fri, apr 1, you name it.

$ fselect path from /home/user where modified = today
$ fselect path from /home/user where accessed = yesterday
$ fselect path from /home/user where modified = 'last fri'
$ fselect path from /home/user where modified gte 2024-01-01

Get more specific with time intervals:

# everything created between 3PM and 4PM on May 1st
$ fselect path from /home/user where created = '2024-05-01 15'

# down to the minute
$ fselect path from /home/user where created = '2024-05-01 15:10'

Complex conditions with parentheses:

$ fselect "name from /tmp where (name = '*.tmp' and size = 0) or (name = '*.cfg' and size > 1000000)"

File Type Shortcuts easy

Boolean columns for common file types. No need to remember extensions — just ask!

$ fselect path from /home/user where is_image
$ fselect path from /home/user where is_video
$ fselect path from /home/user where is_doc
$ fselect path, mime from /home/user where is_audio
$ fselect path from /home/user where is_archive
$ fselect path from /home/user where is_source

Pattern Matching & Regex medium

Simple globs just work with = and !=:

$ fselect name from /home/user where path = '*Rust*'

Full regex support (Rust flavor) with the =~ operator:

$ fselect name from /home/user where path =~ '.*Rust.*'
$ fselect "name from . where path !=~ '^\./config'"

SQL-style LIKE patterns (% = any chars, _ = single char, ? = optional char):

$ fselect "path from /home/user where name like '%report-2024-__-__???'"

When you want exact matching (no glob expansion), use ===:

$ fselect "path from /home/user where name === 'some_*_literal_*_name'"

Search Options medium

Search multiple directories, control depth, follow symlinks, and look inside archives:

# multiple search roots
$ fselect path from /home/user/old, /home/user/new where name = '*.jpg'

# limit depth per root
$ fselect path from /home/user depth 3, /tmp depth 1 where is_image

# min and max depth
$ fselect path from /home/user mindepth 2 maxdepth 5 where name = '*.jpg'

# follow symbolic links
$ fselect path, size from /home/user symlinks where name = '*.jpg'

# search inside zip archives
$ fselect path, size from /home/user archives where name = '*.jpg'

# combine everything
$ fselect size, path from /home/user depth 5 archives symlinks where name = '*.jpg' limit 100

# respect .gitignore
$ fselect size, path from /home/user/projects gitignore where name = '*.cpp'

Functions medium

Aggregate functions — get stats about your files. Curly braces work too, if that's your thing.

$ fselect "MIN(size), MAX{size}, AVG(size), SUM{size}, COUNT(*) from /home/user/Downloads"

String and formatting functions:

$ fselect "LOWER(name), UPPER(name), LENGTH(name), YEAR(modified) from /home/user/Downloads"

Year of the oldest file on your system? One-liner:

$ fselect "MIN(YEAR(modified)) from /home/user"

Include arbitrary text in your output:

$ fselect "name, ' has size of ', size, ' bytes'"

Group, Order & Limit medium

Group files by extension and count them:

$ fselect "ext, count(*) from /tmp group by ext"

Order results by size (descending), then by name:

$ fselect path from /tmp order by size desc, name

You can also order by column position:

$ fselect modified, fsize, path from ~ order by 1 desc, 3

Limit and offset — pagination for your filesystem:

$ fselect name from /home/user limit 10
$ fselect name from /home/user limit 10 offset 20

Images & Media medium

Search by image dimensions — find those wallpaper-quality photos:

$ fselect CONCAT(width, 'x', height), path from /home/user/photos where width gte 2000 or height gte 2000

Find perfectly square images:

$ fselect path from /home/user/Photos where width = height

Old-school rap at 320kbps? Say no more:

$ fselect duration, path from /home/user/music where genre = Rap and bitrate = 320 and mp3_year lt 2000

EXIF data — find photos from a specific camera:

$ fselect path, exif_make, exif_model from /home/user/photos where exif_make = 'Canon'

Permissions & Ownership medium

Find files with dangerous permissions:

$ fselect mode, path from /home/user where other_write or other_exec
$ fselect mode, path from /home/user where other_all

Glob or regex on permission strings:

$ fselect mode, path from /home/user where mode = '*rwx'
$ fselect mode, path from /home/user where mode =~ '.*rwx$'

Find files by owner, SUID, sticky bits:

$ fselect user, group, path from /home where user = mike
$ fselect name from /usr/bin where suid
$ fselect path from /tmp where is_sticky

File Hashes & Content medium

Need to find files by their hash or check for duplicates?

$ fselect sha256, path from /home/user/downloads where name = '*.iso'

Search files by content:

$ fselect path from /home/user/src where contains('TODO') and name = '*.rs'

Subqueries advanced

This is where it gets powerful. Find files with sizes that match files in another directory:

$ fselect "name from /test1 where size in (select size from /test2)"

Find files that exist in production but NOT in backup:

$ fselect "name from /production where name not in (select name from /backup)"

Correlated subqueries with table aliases — check if directories have children:

$ fselect "path from /home/user as parent
  where is_dir and exists (
    select * from /home/user as child
    where child.dir = parent.path
  )"

Nested subqueries — go as deep as you need:

$ fselect "name from /dir1 where size > 100
  and size in (
    select size from /dir2 where name in (
      select name from /dir3 where modified in (
        select modified from /dir4 where size < 200
      )
    )
  )"

Output Formats medium

Pipe it, process it, display it — pick your format with into:

$ fselect size, path from /home/user limit 5 into json
$ fselect size, path from /home/user limit 5 into csv
$ fselect size, path from /home/user limit 5 into html

Extended Attributes & ACLs advanced

Check extended attributes, ACLs, and Linux capabilities:

$ fselect "path, has_xattrs, has_xattr(user.test), xattr(user.test) from /home/user"

# find files with specific ACL entries
$ fselect path, acl from /shared where has_acl

# find binaries with Linux capabilities
$ fselect path, caps from /usr/bin where has_caps

Interactive Mode easy

Fire up the REPL and explore interactively. No shell escaping headaches, command history, the works:

$ fselect -i
# now you're in interactive mode!

fselect> name, size from . where is_image
fselect> cd /home/user/photos
fselect> path where width > 1920
fselect> exit

Real-World Combos advanced

Find the top 10 biggest source files, sorted by size:

$ fselect fsize, path from ~/projects where is_source order by size desc limit 10

Get a breakdown of file types in a directory:

$ fselect "ext, count(*), sum(size) from ~/Downloads group by ext order by 3 desc limit 20"

Find empty directories:

$ fselect path from /home/user where is_dir and is_empty

Find all files NOT in your backup by comparing two directories:

$ fselect "name, path, size from /data as data
  where not exists (
    select * from /backup as backup
    where backup.name = data.name
  )"

Disk usage stats for your downloads folder, as JSON:

$ fselect "ext, count(*), format_size(sum(size), '%.1 ds') from ~/Downloads group by ext order by sum(size) desc limit 10 into json"

Find scripts (files starting with a shebang) that aren't executable:

$ fselect mode, path from /home/user/scripts where is_shebang and not user_exec

Photos taken with a Canon at ISO 100 with wide aperture, sorted by date:

$ fselect "exif_dto, exif_f_num, exif_iso, path from ~/photos
  where exif_make = 'Canon' and exif_iso = 100 and exif_f_num < 2.8
  order by exif_dto desc"

Path Terminology

A visual cheat sheet for the path-related columns.

File naming terminology diagram showing how abspath, absdir, path, dir, name, filename, and ext relate to a file path

Quick Reference

The cheat sheet you'll actually keep open in another tab.

Columns

Path & Name

  • name — file name (with extension)
  • filename — name without extension
  • ext — extension
  • path — relative path
  • abspath — absolute path
  • dir — relative directory
  • absdir — absolute directory

Size

  • size — size in bytes
  • fsize / hsize — human-readable size

Timestamps

  • accessed — last access time
  • created — creation time
  • modified — last modification
  • atime / mtime / ctime — Unix timestamps

File Type Booleans

  • is_dir is_file is_symlink
  • is_pipe is_char is_block is_socket
  • is_hidden is_empty is_shebang
  • is_binary is_text

Type Shortcuts

  • is_archive is_audio is_book
  • is_doc is_font is_image
  • is_source is_video

Permissions (Unix)

  • mode — permission string
  • user_read / user_write / user_exec / user_all
  • group_read / group_write / group_exec / group_all
  • other_read / other_write / other_exec / other_all
  • suid sgid sticky

Ownership

  • uid / gid — numeric IDs
  • user / group — names

Device & Inode (Unix)

  • device — device code
  • rdev — device ID for special files
  • inode — inode number
  • blocks — 256-byte blocks
  • hardlinks — number of hard links

Content & Hashes

  • mime — MIME type
  • line_count — number of lines
  • sha1 sha256 sha512 sha3

Image & Media

  • width / height — dimensions
  • title album artist genre
  • bitrate freq duration mp3_year
  • exif_* — 40+ EXIF fields

Extended Attributes

  • has_xattrs / xattr_count
  • acl / has_acl
  • default_acl / has_default_acl
  • caps / has_caps
  • extattrs / has_extattrs

Operators

OperatorAliasesDescription
===, eqEqual (with glob expansion)
!=<>, neNot equal
===eeqStrict equal (no glob/regex)
!==eneStrict not equal (no glob/regex)
=~~=, regexp, rxRegex match
!=~!~=, notrxRegex not match
>gtGreater than
>=gte, geGreater than or equal
<ltLess than
<=lte, leLess than or equal
likeSQL LIKE pattern match
notlikeSQL LIKE pattern not match
betweenRange check
not betweennotbetweenNot in range
inSubquery IN
not innotinSubquery NOT IN
existsSubquery EXISTS
not existsnotexistsSubquery NOT EXISTS
andANDLogical AND
orORLogical OR
notNOTLogical NOT
+plusAddition
-minusSubtraction
*mulMultiplication
/divDivision
%modModulo / remainder

Functions

FunctionDescription
COUNT, MIN, MAX, AVG, SUMAggregate functions
STDDEV, STDDEV_SAMPPopulation / sample standard deviation
VARIANCE, VAR_SAMPPopulation / sample variance
LOWER, UPPER, INITCAPCase conversion
LENGTH, CONCAT, CONCAT_WSString operations
SUBSTRING, REPLACE, TRIMString manipulation
LTRIM, RTRIMTrim leading / trailing whitespace
LOCATE / POSITIONFind substring position
YEAR, MONTH, DAY, DOW, DOYDate part extraction
DAYNAMEDay of week name (Monday, Tuesday, ...)
CURRENT_DATE, CURRENT_TIMECurrent date / time
CURRENT_TIMESTAMP, NOWCurrent date and time
DATE_ADD, DATE_SUB, DATE_DIFFDate arithmetic
FROM_UNIXTIMEUnix timestamp to datetime string
LAST_DAYLast day of the month for a date
CURRENT_UID, CURRENT_USERCurrent user ID / username (Unix)
CURRENT_GID, CURRENT_GROUPCurrent group ID / name (Unix)
CONTAINSFile content search
FORMAT_SIZEHuman-readable file size
FORMAT_TIMEHuman-readable duration
ABS, POWER, SQRT, LOG, LN, EXPMath functions
FLOOR, CEIL, ROUNDRounding functions
LEAST, GREATESTMin / max of multiple values
PIPi constant (3.14159...)
RANDOMRandom number generation
BIN, HEX, OCTNumber base conversion
TO_BASE64, FROM_BASE64Base64 encoding / decoding
CONTAINS_JAPANESE, CONTAINS_KANAJapanese character detection
CONTAINS_HIRAGANA, CONTAINS_KATAKANAHiragana / katakana detection
CONTAINS_KANJIKanji character detection
CONTAINS_GREEKGreek character detection
HAS_XATTR, XATTRExtended attribute access
HAS_EXTATTRExtended file attribute flag check (Linux)
HAS_ACL_ENTRY, ACL_ENTRYPOSIX ACL entry check / read (Linux)
HAS_DEFAULT_ACL_ENTRY, DEFAULT_ACL_ENTRYDefault POSIX ACL entry check / read (Linux)
HAS_CAPLinux capabilities check
COALESCEFirst non-empty value

Size Units

UnitMeaningSize
k, kibKibibyte1,024 bytes
kbKilobyte1,000 bytes
m, mibMebibyte1,048,576 bytes
mbMegabyte1,000,000 bytes
g, gibGibibyte1,073,741,824 bytes
gbGigabyte1,000,000,000 bytes
t, tibTebibyte1,099,511,627,776 bytes
tbTerabyte1,000,000,000,000 bytes

Output Formats

FormatDescription
tabsTab-separated columns (default)
linesEach column on a separate line
listNULL-separated (like find -print0)
csvComma-separated values with header
jsonArray of JSON objects
htmlHTML document with a table