sed Part III · Module 8 · sed in Shell Automation
When to Use Tcl or Python Instead
This is the chapter the track has been pointing at since Chapter 1.3, and it is worth more now than it was then, because you have spent seven modules finding out exactly what sed costs. The question it answers is the one to ask before writing a one-liner rather than after: is this a sed job at all? There is a single test that decides it, and it is sharper than taste — a change sed can make is one that is knowable from the current line alone, with no arithmetic and no structure. Everything else routes somewhere, and where it routes is decided by where the data lives rather than by preference.
Intermediate18 min readsedPart IIITool SelectionawkPython
Part III · Module 8 · Chapter 8.4 · When to Use Tcl or Python Instead
1. The Question
Can this change be decided from the current line alone, with no arithmetic?
If yes, it is a sed job. If no, it is not, and no amount of cleverness will make it one comfortably.
That test is not a style preference. It falls directly out of what Part I measured: Chapter 2.1 showed sed holds one line and forgets it, Chapter 2.2 showed the pattern space is cleared every cycle, and the only escape — the hold space in Chapter 6.1 — carries exactly one piece of text with no way to compute on it.
2. Where sed Is Genuinely the Right Tool
Worth stating clearly, because a chapter about limits reads as a chapter about weakness and this one is not.
cat sta/slack.rptalu 1.842
fifo -0.110
regf 0.258sed 's/^\([a-z]*\)/BLOCK \1/' sta/slack.rptBLOCK alu 1.842
BLOCK fifo -0.110
BLOCK regf 0.258Each line's new content is a function of that line and nothing else. That is the shape, and when the shape fits, sed is the best tool available: it is everywhere, it needs no interpreter, it streams in bounded memory, and it composes into a pipeline. Rewriting a path across four hundred filelists is a sed job and always will be.
3. The Four Questions
Ask them in order; the first "yes" decides it.
| Question | If yes | Why |
|---|---|---|
| Does it need another line? | awk | sed clears the buffer every cycle |
| Does it need a number? | awk | sed has no arithmetic at all |
| Does it need structure? | Python | nested or quoted formats are not line-shaped |
| Does it need the tool's own data? | Tcl | the data only exists inside the tool |
| None of the above | sed | line-local text is exactly its job |
Sections 4 to 7 are each of those, with the evidence.
4. "It Needs a Number" — the Clearest Cut
sed has no arithmetic. Not limited arithmetic — none. It cannot add, compare magnitudes, or tell you that -0.110 is less than 0.258.
The demonstration needs no second language. Ask the shell to sort those three rows by their second column:
sort -k2 sta/slack.rptalu 1.842
regf 0.258
fifo -0.110That is text order: 1 before 0 before -. The violated path, the one that matters most, sorted last. Now ask for numeric order:
sort -k2 -g sta/slack.rptfifo -0.110
regf 0.258
alu 1.842Completely different. A tool that treats -0.110 as a string will put it after 1.842 every time, and sed is such a tool — there is no flag that changes this, because there is nothing in sed that knows what a number is.
So any threshold is not a sed job. "List the paths with negative slack", "flag anything under 50 ps", "total the area column" — all of these look like text operations and none of them are.
awk does all three in a line:
awk '{ t += $2 } END { printf "%.3f\n", t }' sta/slack.rpt1.990awk '$2 < 0 { n++ } END { print n+0 }' sta/slack.rpt1awk 'NR==1 || $2 < w { w=$2; b=$1 } END { print b, w }' sta/slack.rptfifo -0.110Total, count, and worst case. Each is shorter than the sed that cannot do it.
5. "It Needs Another Line" — and the Hold-Space Temptation
Chapter 6.1 showed the hold space carrying a startpoint down to its slack line, and it genuinely worked. So the boundary here is not "sed can never see two lines" — it is about cost.
The hold space holds one thing. Two pieces of state means encoding both into one buffer and parsing them back out with substitutions, and the script stops being readable at about the third command. Chapter 6.1's own closing advice was that tac exists and is better than the reverse-a-file idiom.
The honest rule: one piece of carried context is a defensible sed job; two is an awk job. awk has variables and arrays, and the equivalent of Chapter 6.1's pairing is a single assignment:
awk '/^Startpoint/ { sp = $0 } /slack/ { print $0; print sp }'No buffers, no h/G/x, and adding a second thing to remember is another variable rather than a redesign.
6. "It Needs Structure" — Python
Some formats are not line-shaped. A quoted CSV field containing a comma, a JSON report, an XML netlist, a Liberty file with nested groups — in all of these the meaning of a character depends on what came before it, possibly many lines before.
A line-based tool cannot see that context, and every attempt produces a pattern that works until it meets a quoted delimiter. Python is present here:
python3 -VV | head -1Python 3.13.5 (v3.13.5:6cb20a219a8, Jun 11 2025, 12:23:45) [Clang 16.0.0 (clang-1600.0.26.6)]and the structural version of the same three rows is a parse, not a pattern:
python3 -I -c "
import json
rows = [l.split() for l in open('sta/slack.rpt')]
print(json.dumps([{'block': b, 'slack': float(s)} for b, s in rows]))
"[{"block": "alu", "slack": 1.842}, {"block": "fifo", "slack": -0.11}, {"block": "regf", "slack": 0.258}]Note float(s) — the moment the values become numbers, every comparison in section 4 is available, and a malformed row raises rather than silently producing text.
The other reason to reach for Python is tests. A sed one-liner has no unit tests and no way to get them. A transformation that is load-bearing for a flow — one that will be run unattended, on data you have not seen, for years — deserves to be a program with a test file next to it. That is not a statement about Python's syntax; it is about whether the thing can be verified by anyone other than its author.
7. "It Needs the Tool's Own Data" — Tcl
The last case is different in kind, and the chapter has to be honest about its evidence.
EDA tools — Design Compiler, PrimeTime, Innovus, Tempus — embed Tcl, and inside them your script can ask the tool directly: get_cells, get_timing_paths, report_timing -json. The data is the tool's live database, and the only way to reach it is the tool's own API.
Doing that with sed means waiting for the tool to print a report and then parsing its text. That works, and it is what Part IV's timing-report chapters are about, but it is strictly worse when you have the alternative:
- The report is a rendering of the data, with columns that move, numbers already rounded, and lines wrapped for a terminal.
- A Tcl query returns the value, not its printed form — no parsing, no rounding, no
[[:space:]]\{2,\}to squeeze. - A tool's report format changes between releases. Its Tcl API changes far less.
Rule: if the question can be asked inside the tool, ask it there. Parse the report only when you cannot — a report from a vendor you cannot script, a log from a run that has already finished, a file produced by something with no API at all. Those are real and common, which is why the rest of this track exists.
8. A Worked Decision
A real request: "produce a summary of every timing path whose slack is worse than −50 ps, with its startpoint."
Run the four questions:
- Another line? Yes — the startpoint and the slack are on different lines.
- A number? Yes — "worse than −50 ps" is a numeric comparison, and section 4 showed text order is not numeric order.
- Structure? No, a timing report is line-shaped.
- The tool's own data? If you can run this inside PrimeTime, yes — and then it is a Tcl one-liner over
get_timing_paths -slack_lesser_than.
So: Tcl if you have the tool, awk if you have only the report. Not sed, and the reason is question 2 on its own — a threshold is arithmetic.
Where sed still helps is as a preparation stage, exactly as Chapter 8.1 described: normalise the report so awk's job is trivial. That is a pipeline with one job per stage, and sed doing the job it is good at.
9. Think It Through
1. Give the one-sentence test.
Can this change be decided from the current line alone, with no arithmetic? Yes is sed; no is not.
2. Why is "delete every line where column 3 exceeds 100" not a sed job, even though it looks like line-local filtering?
Because "exceeds 100" is a numeric comparison and sed has none. It can match the text 100, and it cannot tell that 99.5 is less than it while 1000 is more. Section 4's sort proves the general case: to a text tool, -0.110 sorts after 1.842. This is awk '$3 <= 100'.
3. When is the hold space a defensible choice over awk?
When you are carrying exactly one piece of context, the script stays at three or four commands, and adding awk to the pipeline would be the only reason awk is there. Chapter 6.1's startpoint-to-slack pairing qualifies. Two pieces of state do not — that is encoding a record in a buffer, and awk has had variables all along.
4. Your flow parses report_timing output with a 40-line sed script, and it breaks after a tool upgrade. What is the real diagnosis?
That the flow is parsing a rendering rather than querying data. The report format changed because report formats do; the tool's Tcl API almost certainly did not. The fix is not a better sed script — it is asking the question inside the tool, and keeping sed for the cases where no API is available.
5. You can do it in sed with a t loop and the hold space. Should you?
Ask who maintains it. A loop plus hold space is at the edge of what Chapter 6.3 could even make portable — the compact label form fails silently on BSD — and it has no tests. If it is a one-off you will run today and read never, fine. If it is flow code, the question is not whether sed can but whether anyone else can change it safely in a year.
6. Does this chapter argue sed is a weak tool?
No — it argues sed has a shape. Within it, sed is unbeatable: available everywhere, no interpreter, bounded memory on any file size, and composable. Chapter 2.1 measured an 18 MB file processed in 1.47 MB of memory. The failure mode is not using sed; it is using sed for a job whose shape is different, and then adding machinery until it almost fits.
10. Summary
- One test: can the change be decided from the current line alone, with no arithmetic? Yes is sed.
- Four routing questions, first yes wins: another line → awk; a number → awk; structure → Python; the tool's own data → Tcl.
- sed has no arithmetic.
sort -k2put1.842first and-0.110last because string order is not numeric order;-greversed it. Any threshold is therefore not a sed job. - awk does total, count and worst-case in one line each, on data sed cannot compare at all.
- One carried context is a defensible hold-space job; two is an awk job. awk's version of Chapter 6.1's pairing is one variable assignment.
- Structure means Python — quoted CSV, JSON, XML, Liberty.
float()also makes every numeric comparison available, and a malformed row raises instead of passing through as text. - Python also means tests. A transformation that runs unattended for years should be verifiable by someone other than its author.
- If the question can be asked inside the EDA tool, ask it there. A report is a rendering; the Tcl API is the data, and report formats change while APIs mostly do not.
- This section is argued, not measured — no EDA tool exists on the machine these examples were run on, and no transcript was invented to pretend otherwise.
- sed is not weak, it has a shape. Within it nothing beats it; outside it, no amount of machinery makes it fit.
That closes Part III, and with it everything about using sed responsibly: the language, the safety, the composition, and the judgement about whether to reach for it at all. Part IV — Semiconductor Applications applies all of it to the work itself, starting with Module 9 — RTL and Filelist Maintenance: migrating a filelist when the tree moves, renaming identifiers across RTL with the word boundaries Chapter 7.3 introduced, and stating plainly where text-based refactoring of a hardware language stops being safe.
Where this fits
Part of the sed curriculum.
