Analysis
Five Command-Line Checks Before Publishing a Website

A useful publishing command produces a result that can pass or fail. These five checks cover contradictory copy, HTTP behavior, executable site rules, remote deployment state, and the final patch before publication.
The original CSV command was the warning
The old page included a sed expression intended to turn tab-separated MySQL output into CSV. It replaced tabs with quoted commas, put a quote at each end of the line, and removed newline characters. That looked compact enough to remember. It was not a CSV writer.
A field containing a quote needs escaping. A field containing a comma needs correct quoting. A field containing a newline cannot be repaired by deleting every newline after the query. Database credentials should not be left in shell history as a convenient -pPASSWORD argument. The command solved the shape of one familiar result, not the data format it claimed to produce.
I now treat that kind of one-liner as a prototype. If the output has a real grammar—CSV, JSON, XML, HTML, SQL—I use a parser or serializer for that grammar. I keep sed and awk for line-oriented text where the delimiter and failure cases are genuinely controlled.
The lesson survived even though the command did not: short is useful only when the boundary is honest.
1. I search for contradictions before I read everything
This site is assembled from WordPress content, small PHP migrations, reusable plugins, a revenue ledger, and JavaScript verification scripts. A count or product statement can be correct in one file and stale in three others. Reading every file from top to bottom is a poor way to find that class of error.
For the latest release, the public site moved from 32 to 33 evidence-backed posts. I used this search after updating the operating record:
rg -n --pcre2 'thirty(?!-three)|32 current|47 mapped|45 indexable' \
REVENUE-MODEL.md
No output was the expected result. Earlier output would have been more useful than a green result because it would have named the exact stale line. The same pattern works for editorial promises:
node audit-article-draft.cjs restore-cli-usefulness.php
rg -n 'old doorbell|S1 vacuum|Matter bulb' -g '*.php' -g '*.md'
The first search protects the first-person publication voice. The second is not an automatic fact checker; it is a review queue for claims that have changed or need a boundary. A match can be correct inside a historical explanation. The command finds attention, not truth.
That distinction matters. A search result is evidence that text exists. It is not evidence that the text is accurate, current, public, or visible to a reader. I still inspect the surrounding source and the rendered destination.
2. I ask the server what it actually returned
A browser can make a broken page look healthy. It follows redirects, caches assets, applies a theme, and gives a friendly error page almost the same visual weight as a real article. For a publishing check, I want the status, content type, and final URL separated from the page design.
curl -sS --fail-with-body -o /dev/null \
-w '%{http_code} %{content_type} %{url_effective}\n' \
https://hackyourworld.com/ads.txt
During this rebuild, that returned:
200 text/plain https://hackyourworld.com/ads.txt
I fetched the body separately and confirmed that the single publisher record matched the configured AdSense account. I also test the apex and www hosts over HTTP and HTTPS with the advertising crawler user agent because those are distinct paths from an ad crawler’s point of view.
The flags are not decoration. -sS suppresses the progress meter but keeps errors. --fail-with-body gives HTTP errors a failing exit status while preserving their response body when it is needed. -w emits values curl measured rather than text scraped from the page.
I do not use a successful TLS connection as a successful page test. A server can return a polished 404, HTML where a text file is required, or a redirect to the wrong canonical host. The useful check names the contract.
3. I make site rules executable instead of remembering them
The public regression script is longer than any one-line command because the site has more than one invariant. It fetches every managed page and article, then checks one H1, one canonical URL, one search description, a bounded title, the AdSense loader, indexability, article metadata, image metadata, navigation, and archive privacy.
The important shell feature is still simple:
node check-live.cjs
echo $?
A zero exit status means every assertion in that run passed. A nonzero status stops the release. Node’s assertion failures naturally terminate with an error; checks that collect several findings can set process.exitCode = 1 and finish printing the report before the process exits.
The latest complete run checked 33 public posts, 48 mapped URLs, 46 indexable snippets, 33 featured images, 33 curated related-reading maps, eight GitHub referral paths, and 35 calculator cases. Those numbers are not a quality score. They are the scope of the mechanical verification.
A passing link checker does not prove that a 1,600-word article sounds human. A passing snippet audit does not prove that Google will use the description. A passing image audit does not make a generated hero product photography. I keep those limits in the article and in the operating record because an executable check becomes dangerous when its name promises more than its assertions cover.
4. I run a check where its evidence actually exists
The WordPress database and web-server logs live on the server. Copying either into an article workspace would create a new sensitive artifact and make freshness harder to reason about. SSH already supports executing one noninteractive command on the remote host, so I send the narrow check to the data instead.
ssh deploy@example.net 'php /srv/release/test-affiliates.php'
ssh deploy@example.net 'python3 /srv/release/traffic-report.py'
The affiliate check reads the live WordPress configuration and fails if an inactive program leaks a link, a destination host falls outside its allowlist, a sponsored attribute is missing, or the Amazon disclosure appears before activation. The traffic report reads the server logs but emits only aggregate counts, daily totals, referrer hosts, and landing paths. It does not print addresses, query values, or raw lines.
This separation is intentional. The local machine holds the test source. The server holds the production state. SSH carries the command and returns the bounded result. A copied database dump would be broader, more sensitive, and stale as soon as the next request arrived.
I still avoid turning SSH into an invisible deployment language. The remote command uses an explicit release path. A migration checks the expected WordPress theme, slug, post ID, and category before writing. It creates a private checkpoint before changing the post. If any guard fails, the script stops instead of searching for a nearby target.
5. I inspect the patch, not just the final file
A final file can look correct while hiding an accidental deletion elsewhere. Git gives me two different questions:
git diff --check
git diff -- README.md
The first rejects introduced conflict markers and configured whitespace errors. The second shows the actual unstaged change to the named file. Before the Peared article went live, the repository change was one contextual README link. git diff --check was clean, the branch became pull request #15, GitHub CI passed in 29 seconds, and the change merged.
That sequence did not prove the article’s Bluetooth claims. The repository history and source review did that work, with explicit limits where the Go toolchain and live hardware were unavailable. Git proved that the referral edit was narrow, reviewable, and preserved in history.
I prefer a small diff because it keeps the question small. “Is this one field-notes link accurate?” is reviewable. “Did an automated cleanup rewrite the README correctly?” is much harder, even if both versions end with valid Markdown.
What each command can and cannot prove
| Question | Check | What passes | What remains human work |
|---|---|---|---|
| Did stale wording survive? | rg |
The named pattern has no unexpected match | Whether a different phrase makes the same false claim |
| Did the endpoint return the required response? | curl |
Status, type, redirect, and selected body rules | Whether a crawler has processed the response |
| Does the public site preserve its contracts? | Node assertions | Every implemented invariant in the run | Voice, usefulness, factual completeness, ranking |
| Does production match the configured gate? | SSH plus a narrow remote checker | The current server-side assertions | Anything the checker did not read |
| Is the proposed source change mechanically clean? | git diff --check |
No covered whitespace error or conflict marker | Correctness, security, and product judgment |
The command line does not create traffic
None of these commands makes Google rank a page or makes an ad network approve a site. The revenue connection is less magical: a search landing page cannot earn anything if it redirects incorrectly, disappears behind the archive gate, ships a broken canonical, omits the ad loader, or publishes a stale product claim that destroys trust.
The old version of this URL had one historical Google-referrer landing. That is not enough demand to justify a broad command-line content strategy. It is enough reason to stop serving a private, obsolete page when I can replace it with a real account of the current publishing system.
I would still choose the next article from Search Console and referral evidence, not from a desire to write another tool list. The terminal supports the work. It is not the editorial plan.
My pre-publication sequence
- Search the draft and supporting files for forbidden voice, stale counts, old product history, and private identifiers.
- Run a draft audit for length, title, excerpt, and first-person singular voice.
- Lint the focused migration and verify that its target guards match current production.
- Create the server-side checkpoint, publish once, and record exactly what changed.
- Fetch the live URL directly and inspect its status, content type, canonical, metadata, image, and internal links.
- Run the complete public suite plus the server-side affiliate gate.
- Inspect and commit only the intended repository referral, then wait for its actual CI result.
- Update the revenue ledger with measured counts and the limits of the test.
That sequence is slower than pasting a remembered one-liner. It is faster than discovering after indexing that the wrong page, wrong claim, or wrong link went public.
What these checks covered
I used ripgrep 15.2.0, curl 8.21.0, Git 2.55.0, the site’s current Node verification scripts, and narrow SSH commands during this release. The behavior described here is cross-checked against the official ripgrep guide, curl manual, Git diff documentation, OpenSSH manual, and Node process documentation.
I ran the searches, public HTTP checks, public verification scripts, server-side affiliate check, and Peared diff inspection described above. I did not recreate the old MySQL export, test arbitrary CSV edge cases, inspect private visitor records, request a Search Console recrawl, or claim that a passing mechanical suite predicts rankings, AdSense approval, or revenue.