for-each is a small, cross-platform Unix-style utility that executes a command once for each line of input, with positional variable expansion and no shell evaluation.
# Do a command for all folders in current directory
ls -d * | for-each echo
# Echo each line
printf "foo\nbar\n" | for-each echo
# Same idea, from a file
cat urls.txt | for-each echo
cat urls.txt | for-each wget
# Show line numbers
cat file.txt | for-each echo '$#'
# Clone many repositories
cat repos.txt | for-each git clone
# Use fields from tab-separated input
printf "apple\tfruit\ncarrot\tvegetable\n" | for-each echo "$1 is a $2"
# Use the full line explicitly
printf "hello world\n" | for-each echo "Input was: $*"Note: Use single quotes around placeholders (to avoid shell expansion before being passed to for-each): '$1' '$*' '$#'
# Show help and exit
for-each -h
for-each --help
# Show version number and exit
for-each --version
# Do a command for all folders in current directory
ls -d */ | for-each echo
cat repo_list.txt | for-each echo
# Clone multiple repos
cat repo_list.txt | for-each git clone
s# Run a command with replacement
cat urls.txt | for-each wget
# Line numbers
cat src/main.cpp | for-each echo '$#'# Clone many repos (one per line)
cat repos.txt | for-each git clone
# Or with submodules
cat repos.txt | for-each git clone --recurse-submodules# Convert all markdown to HTML
ls *.md | for-each pandoc '$1' -o '$*.html'
# Compress images
ls *.png | for-each convert '$1' -quality 85 'optimized/$1'# Process TSV/CSV with multi-field access
cat data.tsv | for-each \
curl -X POST https://api.example.com -d "user=$1&action=$2&value=$3"
# Generate reports per user
cat users.txt | for-each generate-report --user $1 --output reports/$1.pdf
ls *.* | for-each runai -t "Say hi" --dummy
# Generate prompts for many countries
cat countries.txt | for-each runai -t '"List top 10 longevity research organizations in $1"'# Restart services across many hosts (from file)
cat hosts.txt | for-each ssh '$1' sudo systemctl restart myapp
# Check disk usage on remote servers
cat servers.txt | for-each ssh '$1' df -h /
# Kill processes by name on multiple machines
cat machines.txt | for-each ssh '$1' pkill -f naughty-process
# Download many URLs
cat urls.txt | for-each wget
cat urls.txt | for-each wget -q '$1'
# Resize all videos in a directory
ls *.mp4 | for-each ffmpeg -i '$1' -vf scale=1280:720 r- Reads lines from stdin
- Executes a command once per line
- Simple variable expansion:
$1,$2, … — positional fields$*— entire input line$#— line number (1-based)
- one input line → one argument
- Optional tab-separated fields detected automatically
- Works on Linux, macOS, and Windows
- No runtime dependencies
for-each is intentionally not a CSV (Comma-Separated Values) or text-processing language.
Build with CMake using the helpers:
./build.shOn Windows, build with:
./build.batTo use, install to:
~/.local/bin/for-each
Ensure ~/.local/bin is in your PATH.
MIT License
Copyright © 2026 David Joffe
David Joffe https://djoffe.com https://davidjoffe.github.io https://www.tshwanedje.com