concat is a Zsh function designed to merge the contents of multiple files or files within specified directories into a single output file. It supports filtering by extension, include/exclude patterns, recursive search, and handling hidden files. Developed initially to aggregate files for use as context in Large Language Model (LLM) queries, concat is a versatile tool for developers and system administrators seeking to organize and consolidate project files efficiently.
- Overview
- Features
- Installation
- Quick Start
- Usage
- Options
- Output Filename Logic
- Examples
- Contributing
- Reporting Issues
- Support
- License
concat facilitates the combination of file contents by providing flexible filtering and concatenation options. Whether preparing code snippets for LLMs, consolidating logs, or managing files within larger projects, this tool offers a straightforward and customizable approach.
- Flexible Input: Accepts multiple files, directories, or glob patterns as input.
- Extension Filtering: Select files by one or multiple extensions (e.g., py,js,txt).
- Recursive Search: Traverse directories recursively (default) or limit the search to the top level.
- Include/Exclude Patterns: Filter files based on full path glob patterns. Exclude patterns match against both full path and basename, and simple filenames are treated as **/filename.
- Hidden Files Handling: Option to include hidden files and directories.
- Automatic Text Detection: Automatically skip binary or non-text files during concatenation.
 
- Python Cache Cleanup: Optionally remove __pycache__directories and.pycfiles found in the current working directory.
- Directory Tree Overview: Optionally include a treerepresentation of the current directory in the output.
- Output Formats: Generate output in XML (default) or plain text format.
- Verbose and Debug Modes: Enable detailed logging and execution tracing for troubleshooting.
- Customizable Output: Specify output file names.
Note on directory listing: when the XML includes the optional matched-directories list, all paths are computed relative to the current working directory (CWD). If a matched directory is outside the CWD, its absolute path is shown. This avoids misleading prefixes when glob inputs span multiple roots.
Integrate the concat function into your Zsh environment by selecting one of the following methods based on your preference and setup requirements.
Suitable for users managing multiple custom Zsh functions.
- 
Create a Directory for Custom Functions Ensure a dedicated directory for your custom Zsh functions exists. If not, create one: mkdir -p ~/.zsh_functions
- 
Add the concat.zshFileMove the concat.zshfile into your functions directory:mv /path/to/concat.zsh ~/.zsh_functions/concat.zsh
- 
Configure Your Zsh Profile Open ~/.zshrcand add:# Source all custom Zsh functions from ~/.zsh_functions ZSH_FUNCTIONS_DIR="$HOME/.zsh_functions" if [ -d "$ZSH_FUNCTIONS_DIR" ]; then for funcPath in "$ZSH_FUNCTIONS_DIR"/*.zsh; do [ -f "$funcPath" ] || continue if ! . "$funcPath" 2>&1; then echo "Error: Failed to source \"$(basename "$funcPath")\"" >&2 fi done else echo "Error: \"$ZSH_FUNCTIONS_DIR\" not found or not a directory" >&2 fi unset ZSH_FUNCTIONS_DIR 
- 
Reload Your Zsh Configuration source ~/.zshrc 
Recommended for users who prefer to source the concat function individually.
- 
(Optional) Create a Functions Directory mkdir -p ~/.zsh_functions
- 
Add the concat.zshFilemv /path/to/concat.zsh ~/.zsh_functions/concat.zsh
- 
Configure Your Zsh Profile Open ~/.zshrcand add:# Source the concat function CONCAT_FUNC_PATH="$HOME/.zsh_functions/concat.zsh" if [ -f "$CONCAT_FUNC_PATH" ]; then if ! . "$CONCAT_FUNC_PATH" 2>&1; then echo "Error: Failed to source \"$(basename "$CONCAT_FUNC_PATH")\"" >&2 fi else echo "Error: \"$(basename "$CONCAT_FUNC_PATH")\" not found at:" >&2 echo " $CONCAT_FUNC_PATH" >&2 fi unset CONCAT_FUNC_PATH 
- 
Reload Your Zsh Configuration source ~/.zshrc 
- 
Merge Python files (XML) concat -x py . # -> _concat-py.xml 
- 
Plain text for src/directoryconcat --text src/ # -> _concat-src.txt
- 
Concatenate Markdown files (wildcard) concat -x md '*.md' # -> _concat-md.xml 
- 
Wildcard logs to plain text concat -t '*.log' # -> _concat-log.txt 
- 
Custom output filename concat -o summary.txt project/ # -> summary.txt
- 
Remove old output files concat clean logs/ Pass the same filtering options as regular runs to target specific files. 
concat [OPTIONS] [FILE...]Run concat clean [OPTIONS] [DIR...] to delete existing _concat-* files. This command searches recursively by default; use -n to disable recursion. Other include/exclude flags work the same as for normal runs.
- [FILE...]: One or more files, directories, or glob patterns to process. If omitted, the current directory (- .) is used.
| Option | Short | Description | Default | 
|---|---|---|---|
| --output <file> | -o | Output file name. | _concat-output.xmlor.txt | 
| --recursive | -r | Search directories recursively. | Enabled | 
| --no-recursive | -n | Do not search directories recursively. | Disabled | 
| --text | -t | Output in plain text format instead of XML. | XML | 
| --ext <ext> | -x | Only include files with this extension (e.g., py,txt). Can be repeated. | All | 
| --include <glob> | -I | Include files whose full path matches this glob pattern. | After extension filter | 
| --exclude <glob> | -e,-E | Exclude files matching the glob pattern (full path or basename). | None | 
| --tree | -T | Include a directory tree representation (requires the treecommand). | Disabled | 
| --hidden | -H | Include hidden files and directories. | Disabled | 
| --no-purge-pycache | -P | Do not delete __pycache__directories and.pycfiles. | Purge enabled | 
| --verbose | -v | Show matched/skipped files and settings. | Disabled | 
| --debug | -d | Enable debug mode with Zsh execution tracing ( set -x). | Disabled | 
| --no-dir-list | -l | Do not list input directories at the top of the output. | Disabled | 
| --help | -h | Show the help message and exit. | N/A | 
| Input Scenario | Output Filename | Format | 
|---|---|---|
| -o custom.xml | custom.xml | XML | 
| -x md, all files are.md | _concat-md.xml | XML | 
| -x txt, all files are.txt | _concat-txt.txt | Text | 
| -x py -x js, mixed extensions | _concat-output.xml | XML | 
| No -x, single dir (e.g.src/) | _concat-src.txt | Text | 
| No args, cwd = myproject/ | _concat-myproject.txt | Text | 
| No args, unresolvable basename (e.g. /) | _concat-output.txt | Text | 
- 
Custom output concat -o custom.xml file1.py file2.js # -> custom.xml
- 
Markdown to XML concat -x md docs/ # -> _concat-md.xml
- 
Text to plain text concat -x txt notes/ # -> _concat-txt.txt
- 
Mixed Python and JavaScript concat -x py -x js src/ # -> _concat-output.xml
- 
Single dir default text concat src/ # -> _concat-src.txt
- 
Default in project root concat # -> _concat-myproject.txt
- 
Fallback default concat / # -> _concat-output.txt
- 
Clean up old outputs concat clean -n subdir/ -e '*backup*'
This repository also provides a Rust-based version in concat-rs. Build it:
cd concat-rs && cargo build --release
mv target/release/concat ~/bin/After installing, call concat from Zsh like any command:
concat -x rs src/Run concat --help to see all options.
Contributions are welcome! Whether you're reporting a bug, suggesting a feature, or submitting a pull request, your input helps improve concat.
- 
Fork the Repository Navigate to the repository page and click the "Fork" button to create your own copy. 
- 
Clone Your Fork git clone https://github.com/kgruiz/concat-zsh.git cd concat-zsh
- 
Create a Feature Branch git checkout -b feature/YourFeatureName 
- 
Make Your Changes Ensure your code adheres to the project's coding standards and includes necessary documentation. Update the README if options or behavior change. 
- 
Commit Your Changes git commit -m "Add feature: YourFeatureName"
- 
Push to Your Fork git push origin feature/YourFeatureName 
- 
Open a Pull Request Navigate to the original repository ( kgruiz/concat-zsh) and click "New Pull Request." Provide a clear description of your changes and their purpose.
If you encounter any issues or have feature requests, please open an issue in the repository's Issues section. Include detailed information, steps to reproduce, expected vs. actual behavior, and your environment details (OS, Zsh version) to help maintainers address the problem effectively.
For support, please open an issue in the Issues section of the repository.
This project is licensed under the GNU General Public License v3.0. You are free to use, modify, and distribute this software in accordance with the terms of the license.