Skip to content
AgileLogics
6 min read

Finding Files: find and xargs

Prerequisites: Wildcards and globbing, Pipes: connecting commands

find searches folders (recursively) for files matching conditions — name, type, size, age — and can act on each one.

mkdir -p project/src project/logs project/docs
touch project/src/app.js project/src/util.js project/docs/guide.md
touch project/logs/a.log project/logs/b.log

find project -name "*.js" | sort
echo "---"
find project -type d | sort
echo "---"
find project -name "*.log" -o -name "*.md" | sort
project/src/app.js
project/src/util.js
---
project
project/docs
project/logs
project/src
---
project/docs/guide.md
project/logs/a.log
project/logs/b.log
Test Matches
-name "*.js" name pattern (quote it!); -iname ignores case
-type f / -type d files / directories
-size +10M larger than 10 MB
-mtime +7 modified more than 7 days ago
-newer file modified more recently than file
-maxdepth 1 don't go deeper than one level

Tests are combined with AND by default; -o means OR, and ! means NOT.

Acting on results

mkdir -p logs
touch logs/a.log logs/b.log logs/keep.txt

find logs -name "*.log" -exec echo "would delete:" {} \; | sort
find logs -name "*.log" -delete
ls logs
would delete: logs/a.log
would delete: logs/b.log
keep.txt
  • -exec command {} \; runs a command for each file ({} is replaced with the file name). -exec command {} + passes many files at once, which is faster.
  • -delete deletes matches. Run the same find without -delete first to check what it matches.

A classic cleanup job: find /var/log/myapp -name "*.log" -mtime +30 -delete.

xargs: turning lines into arguments

xargs takes a list from its input and passes it as arguments to a command. Use -print0 and xargs -0 so names with spaces survive:

mkdir -p docs
printf 'hello\n' > "docs/read me.txt"
printf 'a\nb\nc\n' > docs/notes.txt

find docs -name "*.txt" -print0 | xargs -0 wc -l
 3 docs/notes.txt
 1 docs/read me.txt
 4 total

-print0 separates names with a special "null" character that can't appear in file names; xargs -0 splits on it. xargs -P 4 runs up to 4 commands in parallel — covered in Level 3.

Common mistakes

  • Unquoted patterns: find . -name *.js lets the shell expand *.js first (if matching files exist in the current folder), giving confusing results. Always quote.
  • Piping find into a for loop — names with spaces break. Use -exec, -print0 | xargs -0, or while IFS= read -r -d '' file.