A robust Zsh function to list newest files with proper escaping for easy copy/paste operations.
- Lists newest files by modification time
- Handles spaces and special characters in filenames
- Two output formats: escaped (default) and quoted (-q)
- Supports reverse ordering (-r)
- Works with directory hashes, relative and absolute paths
# Create the script
mkdir -p ~/bin
cat > ~/bin/newest << 'EOF'
#!/usr/bin/env zsh
# newest - List newest files with realpaths
#
# USAGE:
# newest [path] [count] [-r] [-q]
#
# OPTIONS:
# path Directory path or hash (default: current directory)
# count Number of files to show (default: 10)
# -r Reverse order (oldest first instead of newest)
# -q Use quoted output (default: escaped output with backslashes)
#
# EXAMPLES:
# newest # Show 10 newest files (escaped: path\ with\ spaces)
# newest 5 # Show 5 newest files (escaped)
# newest -r 3 # Show 3 oldest files (escaped)
# newest ~xmas 5 # Show 5 newest files in ~xmas directory (escaped)
# newest /path/to/dir 3 # Show 3 newest files in specific directory (escaped)
# newest -q 2 # Show 2 newest files (quoted: '/path/with spaces')
# newest -r -q 4 # Show 4 oldest files (quoted)
#
# PROGRAMMATIC USAGE:
# # Default output works directly with most commands
# ls -la $(newest 1)
# file $(newest 2)
#
# # With xargs (works with both formats)
# newest 5 | xargs -I {} command {}
# newest 3 | xargs file
# newest 2 | xargs -I {} echo "Processing: {}"
#
# # With while loop
# newest 5 | while read file; do echo "$file"; done
#
# OUTPUT FORMATS:
# Default (escaped): /path/with\ spaces/file.txt (ready for copy/paste)
# With -q (quoted): '/path/with spaces/file.txt' (alternative format)
#
# Default format is optimized for easy copy/paste and direct command use.
function newest {
local path="."
local count=10
local reverse=false
local quote_output=false
# Parse arguments
for arg in "$@"; do
case "$arg" in
-r) reverse=true ;;
-q) quote_output=true ;;
[0-9]*) count="$arg" ;;
*)
if [[ -d "$arg" || -e "$arg" ]]; then
path="$arg"
else
echo "Usage: newest [path] [count] [-r] [-q]"
echo " path: directory path or hash (default: current directory)"
echo " count: number of files to show (default: 10)"
echo " -r: reverse order (oldest first)"
echo " -q: use quoted output instead of escaped"
return 1
fi ;;
esac
done
# Expand path - use absolute path
local expanded_path
if [[ "$path" == "." ]]; then
expanded_path=$(pwd)
else
# Try to get absolute path
expanded_path="$path"
if [[ ! -d "$expanded_path" ]]; then
echo "Error: Cannot access path '$path'"
return 1
fi
fi
if [[ $reverse == true ]]; then
# Reverse order: oldest first
local files=($expanded_path/*(.om))
local reversed_files=($files[1,-1])
for file in $reversed_files[1,$count]; do
if [[ $quote_output == true ]]; then
# Output with quotes
echo "'$file'"
else
# Output with backslash escaping (default)
printf "%q\n" "$file"
fi
done
else
# Normal order: newest first
for file in $expanded_path/*(.om[1,$count]); do
if [[ $quote_output == true ]]; then
# Output with quotes
echo "'$file'"
else
# Output with backslash escaping (default)
printf "%q\n" "$file"
fi
done
fi
}
# Execute the function with all arguments
newest "$@"
EOF
# Make it executable
chmod +x ~/bin/newest
# Add to PATH if not already there
grep -q 'PATH="$HOME/bin:$PATH"' ~/.zshrc || echo 'PATH="$HOME/bin:$PATH"' >> ~/.zshrc
grep -q 'export PATH' ~/.zshrc || echo 'export PATH' >> ~/.zshrc