Skip to content

Instantly share code, notes, and snippets.

@jpcofr
Created May 9, 2024 09:20
Show Gist options
  • Save jpcofr/c252b937c65dc53341827cc072647b0a to your computer and use it in GitHub Desktop.
Save jpcofr/c252b937c65dc53341827cc072647b0a to your computer and use it in GitHub Desktop.
Consolidates C++ related files into a single markdown file
#!/bin/bash
# Script Name: merge_code.sh
# Description:
# This script searches for source code files in a specified directory and its subdirectories,
# optionally excluding certain directories. It consolidates the contents of these files into a
# single Markdown file named all_sources.md, organizing the code by its relative file path and
# highlighting syntax according to the file type.
#
# Usage:
# ./merge_code.sh search_directory [exclude_dir1] [exclude_dir2] [...]
# - search_directory: The directory where the script will begin searching for source files.
# - exclude_dirN: Optional directories to exclude from the search.
#
# The script supports files with extensions .c, .cpp, .h, and .hpp, as well as CMakeLists.txt.
# Each file's content is appended under a Markdown header with the file's relative path.
# Code blocks in the Markdown file are annotated with appropriate language identifiers
# (e.g., cpp for C++ files) for syntax highlighting.
#
# Requirements:
# - Bash 4.0 or higher due to the use of associative arrays and other advanced scripting features.
# - The script assumes a Unix-like environment with standard utilities like echo, find, cat, etc.
#
# Example:
# To search for source files in /home/user/project excluding the dirs /home/user/project/temp
# and /home/user/project/build, use:
# ./merge_code.sh /home/user/project temp build
#
# Output:
# The script outputs a file named all_sources.md in the current directory containing all the
# consolidated source files formatted as described above.
# Check for at least one argument
if [ "$#" -lt 1 ]; then
echo "Usage: $0 search_directory [exclude_dir1] [exclude_dir2] [...]"
exit 1
fi
SEARCH_DIR=$1
shift # Remove first argument which is the search directory
# Prepare the exclude pattern for find command
EXCLUDE_PATTERNS=()
for exclude_dir in "$@"; do
EXCLUDE_PATTERNS+=(-not -path "*$exclude_dir*")
done
# Function to process each file
process_file() {
local file="$1"
local relative_path="${file#./}"
local language=""
# Determine language for markdown code block
if [[ "$file" == *"CMakeLists.txt" ]]; then
language="cmake"
elif [[ "$file" == *".c" ]]; then
language="c"
elif [[ "$file" == *".cpp" || "$file" == *".hpp" ]]; then
language="cpp"
elif [[ "$file" == *".h" ]]; then
language="c"
fi
# Prepare and append to all_sources.md
{
echo "## $relative_path"
echo ""
echo "\`\`\`$language"
cat "$file"
echo ""
echo "\`\`\`"
echo ""
echo ""
} >> all_sources.md
}
export -f process_file
export SEARCH_DIR
# Find files and exclude directories as specified, then process each file
find "$SEARCH_DIR" -type f \( -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" -o -name "CMakeLists.txt" \) "${EXCLUDE_PATTERNS[@]}" -exec bash -c 'process_file "$0"' {} \;
echo "All sources have been concatenated into all_sources.md."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment