╔═══╗╔═══╗╔═══╗╔═╗ ╔╗ ║╔═╗║║╔═╗║║╔═╗║║║╚╗║║ ║╚══╗║╚═╝║║║ ║║║╔╗╚╝║ ╚══╗║║╔══╝║╚═╝║║║╚╗║║ ║╚═╝║║║ ║╔═╗║║║ ║║║ ╚═══╝╚╝ ╚╝ ╚╝╚╝ ╚═╝
Map, normalize, and generate values across numeric intervals
Working with numeric ranges is a common task in scripting, data analysis, and system monitoring. While powerful tools like awk can perform these operations, their syntax is often verbose and hard to remember for common tasks like remapping, clamping, or generating sequences.
span simplifies these operations, providing a clean, intuitive, and highly composable command-line interface. It adheres to the Unix philosophy: do one thing well, and work seamlessly with other tools via pipes.
span uses flags to determine its mode of operation. Only one operational flag can be used at a time.
-f, --format: Specifies theprintfformat for floating-point output (e.g.,%.3f). To format as an integer, use%.0f.--version: Prints version information and exits.
-r, --remap <src_a> <src_b> <dst_a> <dst_b>: Remaps a value from a source interval to a target interval.- Ex.:
echo 5 | span -r 0 10 100 200->150
- Ex.:
-l, --limit <min> <max>: Restricts (clamps) a value to a given interval.- Ex.:
echo 150 | span -l 0 100->100
- Ex.:
-E, --encompass: Reads a stream of numbers and outputs the minimum and maximum values.- Ex.:
printf "10\n5\n20" | span -E->5 20
- Ex.:
-n, --divide <steps> <a> <b>: Generates a sequence of numbers by dividing an interval.- Ex.:
span -n 4 0 1->0.0\n0.25\n0.5\n0.75
- Ex.:
-e, --eval <a> <b>: Evaluates a parametertwithin an interval.- Ex.:
echo 0.5 | span -e 100 200->150
- Ex.:
-d, --deval <a> <b>: De-evaluates a number to its parametert.- Ex.:
echo 150 | span -d 100 200->0.5
- Ex.:
-R, --random <count> <a> <b>: Generates<count>random numbers within an interval.- Ex.:
span -R 3 0 10-> (Three random numbers between 0 and 10)
- Ex.:
-S, --snap <steps> <a> <b>: Snaps input values to the nearest point on a grid.- Ex.:
echo 4.78 | span -S 10 0 10->5
- Ex.:
-s, --subintervals <steps> <a> <b>: Divides an interval into<steps>equal subintervals.- Ex.:
span -s 2 0 1->0 0.5\n0.5 1
- Ex.:
--spark [<min> <max>]: Generates a sparkline visualization from a stream of numbers.- With 0 arguments: Reads the entire input stream, automatically determines min/max, and renders the sparkline. Not suitable for infinite streams.
- Ex.:
echo "1 5 22 13 5 17 9" | span --spark->▃█▅▃▆▄
- Ex.:
- With 2 arguments (
<min> <max>): Uses a fixed interval for normalization. Ideal for consistent scaling in real-time or comparative views.- Ex.:
echo "0 25 50 75 100" | span --spark 0 100->▃▅▆█
- Ex.:
--spark-width <n>: (Optional) Enables a fixed-width, "sliding window" animation ofncharacters. Ideal for real-time monitoring.- Ex.:
(while true; do echo $(($RANDOM % 100)); sleep 0.1; done) | span --spark 0 100 --spark-width=40(updates in place)
- Ex.:
--spark-color <name>: (Optional) Applies a color to the sparkline using ANSI escape codes.- Predefined colors:
red,green,blue,yellow,cyan,magenta. - Ex.:
echo "1 5 22 13" | span --spark --spark-color=green-> (shows a green sparkline)
- Predefined colors:
- With 0 arguments: Reads the entire input stream, automatically determines min/max, and renders the sparkline. Not suitable for infinite streams.
span provides flexible installation options.
This single command will download and install span to a sensible default location for your system.
User-level Installation (Recommended for most users):
Installs span to $HOME/.local/bin (Linux/macOS) or a user-specific bin directory (Windows).
curl -sSfL https://raw.githubusercontent.com/gregory-chatelier/span/main/install.sh | shSystem-wide Installation (Requires sudo):
Installs span to /usr/local/bin (Linux/macOS).
sudo curl -sSfL https://raw.githubusercontent.com/gregory-chatelier/span/main/install.sh | shYou can specify a custom installation directory using the INSTALL_DIR environment variable:
curl -sSfL https://raw.githubusercontent.com/gregory-chatelier/span/main/install.sh | INSTALL_DIR=$HOME/bin shIf you have Go installed (Go 1.18+ is required):
go install github.com/gregory-chatelier/span@latestConvert a 4-star rating to a percentage.
echo "3.5" | span -r 0 4 0 100
# Result: 87.5Ensure a user-supplied count is not negative before using it.
count="-5"
safe_count=$(echo "$count" | span -l 0 1000)
# safe_count is now "0"Create 5 evenly spaced points between -1 and 1.
span -n -f "%.1f" 5 -1 1
# Result:
# -1.0
# -0.6
# -0.2
# 0.2
# 0.6Quickly see the range of values in a log file.
cat api_response_times.log | span -E
# Result: 52 1250Generate 8 evenly spaced angles (in radians) around a full circle (0 to 2*PI).
# PI is approx 3.1415926535
span -n -f "%.3f" 8 0 6.283185307
# Result:
# 0.000
# 0.785
# 1.571
# ...
# 5.498Here are some more powerful ways to use span by composing it with other tools:
Create dynamic, updating visualizations directly in your terminal for live data streams.
# Simulate CPU usage monitoring with a 40-character wide, green sparkline.
# The sparkline updates in place. Press CTRL+C to stop.
(
# Generate fluctuating random numbers between 0 and 100
for i in $(seq 1 1000); do
echo $(( ($RANDOM % 100) ))
sleep 0.1
done
) | span --spark 0 100 --spark-width 40 --spark-color=greenOutput (updates in place):
[ ▂▃▄▅▆▇█▇▆▅▄▃▂ ]
Convert a color from one range to another. This example takes an 8-bit RGB color value (0-255) and converts it to a floating-point grayscale value (0.0-1.0).
# The RGB value we want to convert (e.g., 192, a light gray)
rgb_value=192
# Use 'deval' to perform an Inverse Lerp: find the parameter 't'
# of the color in the 8-bit RGB space [0, 255].
t=$(echo "$rgb_value" | span -d 0 255)
# Use 'eval' to perform a Lerp: evaluate 't' in the target
# floating-point grayscale space [0.0, 1.0].
grayscale_value=$(echo "$t" | span -e 0.0 1.0)
echo "The RGB value $rgb_value is equivalent to $grayscale_value in grayscale."Use span --deval to normalize the current time within a start and end timestamp to calculate the percentage of a time window that has elapsed.
# Calculate progress of a time window
start_time="2023-10-15 09:00:00"
end_time="2023-10-15 17:00:00"
# Convert to timestamps
start_ts=$(date -d "$start_time" +%s)
end_ts=$(date -d "$end_time" +%s)
current_ts=$(date +%s)
# Normalize current time to a percentage [0, 1]
progress=$(echo "$current_ts" | span -d "$start_ts" "$end_ts")
# Format as a percentage and print
echo "Progress through the day: $(echo "$progress * 100" | bc -l | awk '{printf "%.1f%%", $1}')"
# Use it to draw a simple bar (50 chars wide)
bar_length=$(echo "$progress * 50" | bc -l | awk '{printf "%.0f", $1}')
printf "|[%-50s]|
" "$(printf '#%.0s' $(seq 1 $bar_length))"Output (at 1:00 PM):
Progress through the day: 50.0%
|[######################### ]|
Use span --limit to clamp a user-provided or calculated value to a safe, known range before using it in a script. This prevents errors from out-of-bounds numbers.
# Safely set a system parameter, like screen brightness.
# Get the desired brightness from the first script argument, default to 50.
desired_brightness=${1:-50}
# Use 'span -l' to clamp the value to a safe range [5, 100].
# This prevents setting brightness to 0 (off) or an invalid negative value.
safe_brightness=$(echo "$desired_brightness" | span -l 5 100)
echo "Desired brightness: $desired_brightness"
echo "Setting safe brightness to: $safe_brightness"
# Now, use the sanitized value to call the system command.
# set_screen_brightness --level "$safe_brightness"Use span -n to generate a smooth gradient between two colors. A gradient is simply a series of evenly spaced steps between two endpoints.
# Generate a 10-step gradient from Red (255,0,0) to Yellow (255,255,0).
# We only need to generate the steps for the Green channel, from 0 to 255.
echo "CSS Gradient Steps:"
span -n 10 0 255 | awk '{ printf "rgb(255, %.0f, 0)\n", $1 }'Use span -R to generate a stream of random numbers within an expected range to test scripts or programs.
# Generate 10 random temperature readings between 18.5 and 21.5 degrees.
span -R 10 18.5 21.5 > mock_sensor_data.txt
# You can now use this file to test your processing script.
# ./process_temperatures.sh < mock_sensor_data.txtUse span -S to quantize a value to the nearest valid step. This is useful for things like volume or brightness controls, which often use discrete levels.
# A system volume control uses 20 steps from 0 to 100 (0, 5, 10, ...).
# A script calculates a desired volume of 47.8%.
desired_volume=47.8
# Use 'span -S' to snap this value to the nearest of the 20 steps.
snapped_volume=$(echo "$desired_volume" | span -S 20 0 100)
echo "Desired volume: $desired_volume%"
echo "Snapping to nearest valid level: $snapped_volume%"
# Now, use the clean, snapped value to set the system volume.
# set_system_volume --percentage "$snapped_volume"Use span -s to divide a large task into smaller, independent chunks for parallel processing. This is a powerful way to speed up scripts that handle batch operations.
#!/bin/bash
# Process a large number of items (e.g., 1 to 1000) in parallel batches.
# A function that does the work for one chunk.
# (Here, we just simulate work with 'sleep'.)
do_work() {
start=$1
end=$2
echo "Processing batch from item $start to $end..."
sleep 2
echo "Finished batch $start-$end."
}
export -f do_work # Export the function so xargs can use it
# Use 'span -s' to divide 1000 items into 10 chunks.
# Then, use xargs to run up to 4 'do_work' processes in parallel.
span -s 10 1 1001 | xargs -n 2 -P 4 bash -c 'do_work "$@"' _
echo "All batches processed."This project is licensed under the MIT License - see the LICENSE file for details.