Skip to content

Instantly share code, notes, and snippets.

@WMAL
Created May 13, 2025 16:00
Show Gist options
  • Save WMAL/0ea25d39a3f85788f52792bd8c4ef0af to your computer and use it in GitHub Desktop.
Save WMAL/0ea25d39a3f85788f52792bd8c4ef0af to your computer and use it in GitHub Desktop.
Bash and Rust serve very different purposes. Bash is beloved for quick automation and command chaining, while Rust is renowned for speed and safety. This post explores a practical comparison between the two: how efficiently can they match lines between two large files?
#!/bin/bash
# Rust vs Bash Performance Comparison Script
# ==========================================
#
# Author: Warith Al Maawali
# Copyright (c) 2025 Warith Al Maawali
# License: See /home/kodachi/LICENSE
#
# Version: 1.0.0
# Last updated: 2025-03-23
#
# Description:
# This script compares the performance of Bash and Rust for a simple file comparison task.
# It generates two large text files with slight differences, then measures how long it takes
# for both Bash and Rust implementations to compare them line by line.
#
# Usage:
# ./rust-speed.sh
#
# Output Information:
# - Number of matched lines found by each implementation
# - Execution time in milliseconds for each implementation
#
# Dependencies:
# - rustc: Rust compiler for compiling the Rust implementation
# - bash: For running the script and the Bash implementation
# - date: For timing the Bash implementation
#
# Return Values:
# The script returns 0 on success, 1 if Rust compilation fails
#
# Examples:
# ./rust-speed.sh # Run the performance comparison test
#
# Links:
# - Website: https://www.digi77.com
# - GitHub: https://github.com/WMAL
# - Discord: https://discord.gg/KEFErEx
# - LinkedIn: https://www.linkedin.com/in/warith1977
# - X (Twitter): https://x.com/warith2020
# Check for required dependencies
if ! command -v rustc >/dev/null 2>&1; then
echo "Error: rustc is required but not installed."
exit 1
fi
# Create a directory for test files if it doesn't exist
TEST_DIR="test_files"
mkdir -p "$TEST_DIR"
# Generate two test files for comparison
# file1.txt contains 100,000 lines in the format "Line X"
# file2.txt is identical to file1.txt except every 10th line is changed to "Changed Line X"
echo "Generating test files..."
>"$TEST_DIR/file1.txt"
>"$TEST_DIR/file2.txt"
for i in $(seq 1 100000); do
echo "Line $i" >>"$TEST_DIR/file1.txt"
if ((i % 10 == 0)); then
# Every 10th line in file2.txt is different
echo "Changed Line $i" >>"$TEST_DIR/file2.txt"
else
# All other lines are identical
echo "Line $i" >>"$TEST_DIR/file2.txt"
fi
done
# -------------------
# Bash Comparison
# -------------------
echo "Running Bash file comparison..."
# Record start time in milliseconds
start_bash=$(date +%s%3N)
# Initialize counter for matching lines
matched=0
# Open both files for reading using file descriptors
exec 3<"$TEST_DIR/file1.txt"
exec 4<"$TEST_DIR/file2.txt"
# Read both files line by line and compare
while true; do
# Read a line from each file
read -r line1 <&3 || break # Break loop if end of file1
read -r line2 <&4 || break # Break loop if end of file2
# Compare lines and increment counter if they match
if [ "$line1" = "$line2" ]; then
((matched++))
fi
done
# Close file descriptors
exec 3<&-
exec 4<&-
# Record end time and calculate elapsed time in milliseconds
end_bash=$(date +%s%3N)
elapsed_bash=$((end_bash - start_bash))
# Display results for Bash implementation
echo "Bash matched lines: $matched"
echo "Bash execution time: ${elapsed_bash} ms"
# -------------------
# Rust Comparison
# -------------------
echo "Creating Rust comparison program..."
# Create a Rust source file with equivalent functionality
cat <<'EOF' >"$TEST_DIR/rust_compare.rs"
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::time::Instant;
use std::path::Path;
fn main() {
// Define file paths
let file1_path = Path::new("test_files/file1.txt");
let file2_path = Path::new("test_files/file2.txt");
// Start timing
let start = Instant::now();
// Open both files with proper error handling
let file1 = match File::open(&file1_path) {
Ok(file) => file,
Err(e) => {
eprintln!("Failed to open {}: {}", file1_path.display(), e);
std::process::exit(1);
}
};
let file2 = match File::open(&file2_path) {
Ok(file) => file,
Err(e) => {
eprintln!("Failed to open {}: {}", file2_path.display(), e);
std::process::exit(1);
}
};
// Create buffered readers for efficient line-by-line reading
let reader1 = BufReader::new(file1);
let reader2 = BufReader::new(file2);
// Initialize counter for matching lines
let mut matched = 0;
// Zip both readers together to process lines in parallel
for (line1_result, line2_result) in reader1.lines().zip(reader2.lines()) {
// Safely unwrap lines with error handling
let line1 = match line1_result {
Ok(line) => line,
Err(e) => {
eprintln!("Error reading from file1: {}", e);
continue;
}
};
let line2 = match line2_result {
Ok(line) => line,
Err(e) => {
eprintln!("Error reading from file2: {}", e);
continue;
}
};
// Compare lines and increment counter if they match
if line1 == line2 {
matched += 1;
}
}
// Calculate elapsed time
let duration = start.elapsed();
// Display results
println!("Rust matched lines: {}", matched);
println!("Rust execution time: {} ms", duration.as_millis());
}
EOF
# Compile the Rust program
echo "Compiling Rust program..."
rustc "$TEST_DIR/rust_compare.rs" -o "$TEST_DIR/rust_compare"
# Check if compilation was successful
if [[ $? -ne 0 ]]; then
echo "Rust compilation failed. Is rustc installed correctly?"
exit 1
fi
# Run the compiled Rust program
echo "Running Rust file comparison..."
"$TEST_DIR/rust_compare"
# Calculate and display performance difference
if [[ $elapsed_bash -gt 0 ]]; then
# Get Rust execution time from the output
rust_time=$(grep -o "[0-9]* ms" <<<"$("$TEST_DIR/rust_compare" | grep "execution time")" | grep -o "[0-9]*")
if [[ -n "$rust_time" ]]; then
speedup=$(echo "scale=2; $elapsed_bash / $rust_time" | bc)
echo -e "\nPerformance Comparison:"
echo "Rust is approximately ${speedup}x faster than Bash for this task."
fi
fi
# Cleanup
echo -e "\nCleaning up temporary files..."
# Uncomment the line below to enable cleanup
# rm -rf "$TEST_DIR"
echo "Test completed successfully."
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment