Skip to content

Instantly share code, notes, and snippets.

@rmohta
Created June 22, 2025 18:25
Show Gist options
  • Save rmohta/7c7bc01e407b04f11ab203221f2f7dba to your computer and use it in GitHub Desktop.
Save rmohta/7c7bc01e407b04f11ab203221f2f7dba to your computer and use it in GitHub Desktop.
Like flatMap, but for directories on your computer.
#!/bin/bash
# Script Name: flatDirectory
# Purpose: Copies all files from the specified folder path and its nested subdirectories
# into a new directory named 'flatDirectory' within the source directory.
# Files from subdirectories will have their names prefixed with the
# subdirectory path relative to the source folder (e.g., 'subdir_filename.txt').
# Check if a source directory is provided as an argument
if [ -z "$1" ]; then
echo "Usage: $0 <source_folder_path>"
echo "Example: $0 ~/Documents/my_project"
exit 1
fi
SOURCE_DIR="$1"
# Check if the provided source directory exists and is a directory
if [ ! -d "$SOURCE_DIR" ]; then
echo "Error: Source directory '$SOURCE_DIR' does not exist or is not a directory."
exit 1
fi
# Define the target flat directory name (created inside the SOURCE_DIR)
FLAT_DIR="$SOURCE_DIR/flatDirectory"
# Create the flat directory if it doesn't exist
# The -p option ensures parent directories are also created if needed, and
# suppresses errors if the directory already exists.
echo "Creating target directory: $FLAT_DIR/"
mkdir -p "$FLAT_DIR"
echo "Copying files from '$SOURCE_DIR'..."
# Find all regular files (f) starting from the specified source directory
# -print0 ensures that filenames with spaces or special characters are handled correctly
# The while loop reads null-separated input from find
find "$SOURCE_DIR" -type f -print0 | while IFS= read -r -d $'\0' filepath; do
# Remove the SOURCE_DIR prefix from the filepath to get the path relative to SOURCE_DIR
# This gives us the path relative to the source directory, e.g., "subdir/file.txt" or "file.txt"
# Ensure the trailing slash is included in the prefix to match directory boundaries correctly
relative_path="${filepath#$SOURCE_DIR/}"
# Extract the base filename (e.g., "file.txt")
filename=$(basename "$relative_path")
# Extract the directory part relative to the source directory (e.g., "subdir")
# If the file is directly in SOURCE_DIR, directory_part will be ".".
directory_part=$(dirname "$relative_path")
# Construct the new filename for the flattened directory
# If the file is in the root of the SOURCE_DIR, directory_part will be ".", so we just use the original filename.
# Otherwise, replace '/' with '_' in the directory_part and prepend it to the filename.
if [ "$directory_part" = "." ]; then
# File is directly in the source folder, no prefix needed
new_filename="$filename"
else
# File is in a subdirectory of the source folder, prepend flattened path
# Replace all '/' with '_' in the directory_part
flattened_prefix=$(echo "$directory_part" | tr '/' '_')
new_filename="${flattened_prefix}_${filename}"
fi
# Copy the file to the flat directory with the new name
# -v provides verbose output, showing which files are being copied
cp -v "$filepath" "$FLAT_DIR/$new_filename"
done
echo "Operation complete. All files copied to $FLAT_DIR/."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment