This article focuses strictly on extracting filenames—no permissions, no timestamps, no extra metadata.
I. TL;DR: Choose by scenario
- Basename only from a full path:
basename /usr/bin/sort→sort. - Single-column listing in the current directory:
ls -1, pipe-friendly. - Find specific types:
find . -maxdepth 1 -name "*.log". - Names with spaces or newlines:
find . -maxdepth 1 -type f -print0 | xargs -0 -I{} basename "{}".
II. basename: strip the directory
basename /usr/bin/sort
basename -s .h include/stdio.h
basename -a /var/log/syslog /etc/passwd
basename outputs only the final path component.[2] Add -s to also strip a suffix; add -a to accept multiple arguments and print one per line. It does not check whether the file exists, so it is safe to use on arbitrary strings.
Sample output:
sort
stdio
syslog
passwd
III. ls single-column and filtered output
ls -1
ls -1 *.conf
ls -F
ls defaults to a multi-column layout; add -1 (digit one) to force single-column output.[1] With shell globbing, the shell expands filenames before passing them to ls, so ls -1 *.conf shows only matching files. -F appends indicators: * for executables, / for directories, @ for symlinks. When reading filenames only, turn off colors with --color=never.
Sample output:
archive.tar.gz
regular.txt
script.sh
IV. find: filter by criteria
find . -maxdepth 1 -type f -name "*.log"
find . -maxdepth 1 -name ".*"
find traverses recursively by default; -maxdepth 1 restricts it to the current directory.[3] -name uses shell-style globbing, -type f limits to regular files, and -name ".*" finds hidden files. find prefixes results with ./; for bare filenames, add -printf '%fn'.
Sample output:
./regular.txt
V. Script safety: spaces and special characters
touch "file with spaces.txt" "weird$name.log"
ls -1
ls -b
find . -maxdepth 1 -type f -print0 | xargs -0 -I{} basename "{}"
When filenames contain spaces, newlines, or tabs, for f in $(find . -name "*.txt") splits on whitespace and produces incorrect results. The correct approach is to let find use NUL delimiters (-print0) and consume them with xargs -0.[3] ls -b converts non-printable characters into C-style escapes, which helps debugging.[1]
Sample output:
file with spaces.txt
weird.log
VI. Rollback, troubleshooting, and limitations
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
find output includes ./ |
Default behavior | Add -printf '%fn' or pipe through sed 's|^./||' |
basename returns empty |
Input is a directory ending with / |
Run realpath first, or remove the trailing slash manually |
ls -1 still shows multiple columns |
Output is being piped or redirected | This is normal; pipes auto-single-column; check for aliases with alias ls |
| Script loses files with spaces | Used for f in $(find ...) |
Switch to -print0 + xargs -0 |
Limitations
lsis a user-space program and does not list hidden files unless-ais explicitly added; admin scripts should not rely onlsparsing—usefindor shell globs directly.find . -maxdepth 1may have poor performance on large directories with NFS mounts; limiting by absolute path is more stable.basenameanddirnameperform string slicing only and do not verify path existence.- When filenames contain newline characters, even
-print0only guaranteesfinddoes not split output; downstream tools still need NUL support.
Test record
- Environment: WSL2 Ubuntu 24.04, kernel 5.15, GNU coreutils 9.4, GNU findutils 4.9.0.
basename /usr/bin/sort→sort;basename -s .h include/stdio.h→stdio.ls -1auto-single-column in pipes;ls -Fappends indicators.find . -maxdepth 1 -type f -print0 | xargs -0 -I{} basename "{}"correctly prints filenames with spaces.- Filenames containing
$need quoting attouch;ls -bshows escaped forms.
References
- [1] ls(1) – Linux manual page (ls(1))
- [2] basename(1) – Linux manual page (basename(1))
- [3] find(1) – Linux manual page (find(1))
Commands were verified on WSL Ubuntu (24.04) and cross-checked against Debian-family and upstream documentation.