Created
May 13, 2025 16:00
-
-
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?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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