A lightweight, dependency-free XML to CSV converter written in pure Bash and AWK. No Python, no Node.js, no external libraries — just standard Unix tools available on any Linux or macOS system.
- Zero dependencies — runs on any system with
bashandawk - Handles single-line, multi-line, self-closing, and empty XML tags
- Properly escapes double quotes in CSV output (
"→"") - Strips Windows-style line endings (
\r) automatically - Outputs to file or stdout for easy piping
- Clear error messages on stderr, clean data on stdout
| Tool | Notes |
|---|---|
bash |
Version 3.2+ |
awk |
Any POSIX-compatible awk (gawk, mawk, nawk) |
tr |
Standard Unix tr utility |
No installation needed beyond what ships with your OS.
# Convert to stdout
./xml_to_csv.sh input.xml
# Convert to a file
./xml_to_csv.sh input.xml output.csv
# Pipe into another command
./xml_to_csv.sh input.xml | sort
./xml_to_csv.sh input.xml | grep "John"Given employees.xml:
<?xml version="1.0" encoding="UTF-8"?>
<employees>
<employee>
<id>1</id>
<name>Alice Smith</name>
<department>Engineering</department>
<email>alice@example.com</email>
</employee>
<employee>
<id>2</id>
<name>Bob Jones</name>
<department>Marketing</department>
<email>bob@example.com</email>
</employee>
</employees>Running:
./xml_to_csv.sh employees.xmlProduces:
id,name,department,email
"1","Alice Smith","Engineering","alice@example.com"
"2","Bob Jones","Marketing","bob@example.com"
The script expects a simple, flat XML structure:
<root> ← any name, treated as container
<record> ← any name, one per row in CSV
<field>value</field>
...
</record>
...
</root>
- Nested XML is not supported — only the immediate children of each record element are extracted as fields
- Field names are taken from the first record; subsequent records follow the same column order
- Fields missing in later records will output as empty strings
| Format | Example | Handled |
|---|---|---|
| Single-line | <name>Alice</name> |
✅ |
| Multi-line | <bio>line1\nline2</bio> |
✅ |
| Self-closing | <nickname/> |
✅ (empty value) |
| Empty tag | <nickname></nickname> |
✅ (empty value) |
| XML declaration | <?xml version="1.0"?> |
✅ (skipped) |
| Comments | <!-- comment --> |
✅ (skipped) |
Errors are written to stderr so they never pollute CSV output when piping:
# Safely redirect data and errors separately
./xml_to_csv.sh input.xml > output.csv 2> errors.log
# Suppress error messages entirely
./xml_to_csv.sh input.xml 2>/dev/null| Error | Cause |
|---|---|
Input file not found |
The specified XML file does not exist |
No records processed |
XML was empty, malformed, or had no matching record tags |
Exit code is 0 on success, 1 on any error.
- Not a full XML parser — does not handle XML attributes, namespaces, CDATA sections, or deeply nested structures
- Multi-line field values are collapsed into a single space-separated line
- Field order in the output is determined by the order they appear in the first record
MIT License. See LICENSE for details.