Reading XML directly in shell scripts is common in lightweight automation, legacy jobs, and restricted runtime environments. This guide explains the classic shell-only pattern, where it breaks, and how to extract XML values more reliably with XPath-capable command-line tools.
Originally published on 2010-05-03; fully revised and updated.

The XML shape this script pattern targets
The original post aimed to read specific fields (changelog, name, date, email) from XML using Bash only. A representative XML file for that use case looks like this:
<entry>
<changelog>Fixed a new bug</changelog>
<name>Shoaib Mir</name>
<date>Sun, 02 May 2010</date>
<email>shoaibmir[@]gmail.com</email>
</entry>Code language: HTML, XML (xml)
What the original grep/sed approach does
The original technique loops over tag names, uses grep/sed to strip tags, then assigns values to variables. A simplified equivalent is:
#!/usr/bin/env bash
for key in changelog name date email; do
output="$(grep "$key" log.xml | tr -d '\t' | sed -e "s#<${key}>##" -e "s#</${key}>##")"
eval "${key}=\"${output}\""
done
echo "$changelog"
echo "$name"
echo "$date"
echo "$email"Code language: PHP (php)
This can work for tightly controlled, single-line XML, but it is fragile for nested elements, attributes, namespaces, multiline text, or repeated nodes. Using eval also increases risk if input is not trusted.
Use XPath tools for safer shell scripts
Option 1: xmlstarlet (shell-friendly XPath queries)
If xmlstarlet is available, it is usually the cleanest CLI option for extracting XML fields in Bash.
#!/usr/bin/env bash
set -euo pipefail
file="${1:-log.xml}"
keys=(changelog name date email)
if ! command -v xmlstarlet >/dev/null 2>&1; then
echo "xmlstarlet is required but not installed" >&2
exit 1
fi
for key in "${keys[@]}"; do
value="$(xmlstarlet sel -t -v "/entry/${key}" -n "$file")"
printf '%s: %s\n' "$key" "$value"
doneCode language: PHP (php)
Option 2: xmllint with XPath
xmllint can also extract scalar values with XPath and is commonly present where libxml2 tooling exists.
#!/usr/bin/env bash
set -euo pipefail
file="${1:-log.xml}"
for key in changelog name date email; do
value="$(xmllint --xpath "string(/entry/${key})" "$file" 2>/dev/null)"
printf '%s: %s\n' "$key" "$value"
doneCode language: PHP (php)
Approach comparison
| Method | Strengths | Limitations | Best fit |
|---|---|---|---|
| grep + sed (+ eval) | No extra XML tool required; fast for trivial input | Brittle parsing; unsafe patterns with untrusted input; fails on many valid XML structures | Short-lived scripts with strictly controlled XML format |
| xmlstarlet sel | Real XML parsing with XPath; script-friendly output | Requires xmlstarlet availability | Reliable extraction in CI/CD scripts and automation jobs |
| xmllint –xpath | Real XML parsing; XPath support; often available in Unix-like environments | XPath output/error handling can need extra care | Environments where xmllint is already installed |
Decision flow for shell-based XML extraction
flowchart TD
A[Need XML values in a shell script] --> B{XML input is strictly controlled}
B -- yes --> C{Only simple flat tags}
C -- yes --> D[Temporary grep sed approach]
C -- no --> E[Use XPath parser]
B -- no --> E[Use XPath parser]
E --> F{xmlstarlet available}
F -- yes --> G[Use xmlstarlet sel]
F -- no --> H{xmllint available}
H -- yes --> I[Use xmllint xpath]
H -- no --> J[Add XML tool dependency]
D --> K[Document limits and migration plan]
G --> L[Add validation and error handling]
I --> L
J --> L
Best practices
- Prefer real XML parsers (
xmlstarletorxmllint) over regex-style parsing. - Avoid
evalunless you completely control input and variable names. - Use
set -euo pipefailin automation scripts and fail fast on missing tools. - Validate input files before extraction and handle empty/missing nodes explicitly.
- If you must keep grep/sed temporarily, document assumptions (single-line tags, no nesting, no namespaces).
Reference and attribution
This revision is based on the original DevOpsSchool post and its cited source: How to read XML file by using shell script? and Reading XML file using shell scripting.
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services — all in one place.
Explore Hospitals