Exporting Project Files into a Markdown Document with Bash

Sometimes you want to collect the contents of several source files into one Markdown file.

This can be useful when you want to:

The following Bash command scans the current directory recursively, finds files with specific extensions, skips unwanted folders like node_modules, and writes everything into a file called project.md.

bash
find . \ \( -type d \( -name "node_modules" -o -name ".git" -o -name "dist" \) -prune \) -o \ -type f \( -name "*.js" -o -name "*.ts" -o -name "*.json" \) \ -not -name "project.md" \ -print0 | while IFS= read -r -d '' file; do rel="${file#./}" printf '/%s\n\n```\n' "$rel" cat "$file" printf '\n```\n\n' done > project.md

What the command does

The command starts from the current directory, represented by ..

bash
find .

This tells find to search inside the folder where the command is run, including all subfolders.

Excluding folders

This part skips folders that should not be scanned:

bash
\( -type d \( -name "node_modules" -o -name ".git" -o -name "dist" \) -prune \) -o

Here, we exclude:

text
node_modules .git dist

That is important because folders like node_modules can contain thousands of files. Including them would make the output huge and usually not useful.

You can add more folders to exclude by extending this section:

bash
-name "node_modules" -o -name ".git" -o -name "dist" -o -name "build"

Choosing file types

This part decides which files should be included:

bash
-type f \( -name "*.js" -o -name "*.ts" -o -name "*.json" \)

It means:

text
include regular files ending in .js, .ts, or .json

You can change this depending on your project.

For example, for Python files:

bash
-name "*.py"

For JavaScript and CSS files:

bash
-name "*.js" -o -name "*.css"

For a React project, you might use:

bash
-name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx"

Avoiding project.md itself

This part prevents the script from reading the output file while it is being created:

bash
-not -name "project.md"

Without this, there is a chance the command could include project.md inside itself, especially if the file already exists.

Handling filenames safely

The command uses:

bash
-print0

and:

bash
while IFS= read -r -d '' file; do

This makes the script safer when filenames contain spaces, quotes, or unusual characters.

For example, a file named:

text
my component.js

will still be handled correctly.

Formatting each file in Markdown

Inside the loop, this line removes the leading ./ from the file path:

bash
rel="${file#./}"

So instead of this:

text
./src/index.js

the output becomes:

text
/src/index.js

Then the script writes the file path into the Markdown file:

bash
printf '/%s\n\n```\n' "$rel"

After that, it writes the actual file content:

bash
cat "$file"

Finally, it closes the Markdown code block:

bash
printf '\n```\n\n'

The final result looks like this:

markdown
/src/index.js ``` console.log("Hello world"); ``` /package.json ``` { "name": "my-project" } ```

Saving everything to project.md

At the end, this part writes all output into a file:

bash
done > project.md

So after running the command, you will get a new file named:

text
project.md

That file will contain the paths and contents of all matched files.

Why this is useful

This is a quick way to turn a project into a readable Markdown snapshot.

It is especially useful when you want to share code without uploading an entire folder, or when you want to provide context to a tool that accepts Markdown input.

You can customize two main things:

The folders to skip:

bash
-name "node_modules" -o -name ".git" -o -name "dist"

And the file extensions to include:

bash
-name "*.js" -o -name "*.ts" -o -name "*.json"

With small changes, this command can work for almost any kind of project.