Skip to content
TechDug

dig-log

Code blocks readers can copy and paste safely

Code blocks readers can copy and paste safely

Readers copy code blocks. They select the text, paste it into a terminal and press Enter, often without reading it closely, because that is what the block seems to invite. So a code block is not only an illustration. It is an instruction that will be executed exactly as written, including every character you did not mean to put there.

These are the conventions we recommend for blocks that people are going to paste. Most of them come down to one rule: what is inside the block should be precisely what the reader needs to type, and nothing else.

Leave the prompt out of the block

Many tutorials start each command with a $ to show that it is typed at a shell prompt. It looks tidy, and it breaks copying. Paste this into bash:

shell
$ npm install

and bash tries to run a program called $, then stops with:

code
bash: $: command not found

In zsh the message reads zsh: command not found: $. Either way, the reader has to go back, work out what happened and edit the line by hand. A block that holds only the command avoids the problem entirely:

shell
npm install

If you want to make clear that a block is meant for a shell, say so in the sentence before it: “Run this in a terminal.” The same goes for # prompts that signal a root shell. In bash, a pasted # turns the line into a comment, so nothing runs and nothing fails, which is worse; in zsh, unless the interactivecomments option is set, it is an error instead. State in the prose that the command needs root, or include sudo in the command itself.

Keep commands and output apart

A block that mixes a command with the text it prints cannot be pasted as a whole. The reader has to select just the first line, and on a phone that is fiddly enough that many will paste everything and get a page of errors.

Put the command in one block and the output in the next, with a short sentence in between such as “You should see something like:”. If you show several commands in a row with no output, one block is fine, as long as every line in it is a command the reader should run, in order:

code
mkdir -p ~/projects/demo
cd ~/projects/demo
git init

Pasting several lines at once runs them one after another, in some shells only once you press Enter. That is convenient when every line is safe, and a reason to split a block whenever one of the lines deserves a moment of thought first.

Use placeholders that fail loudly

Sooner or later a command needs something only the reader knows: a token, a host name, a path. The common habit of writing <your-token> in angle brackets is dangerous in a shell, because < and > are redirection operators. Unquoted, a line like this:

code
echo <name>

does not print anything useful. Bash reads <name as “take input from a file called name” and then finds a > with nothing after it:

code
bash: syntax error near unexpected token `newline'

Worse cases exist. A placeholder such as >output.txt left in a command will silently create or overwrite a file. A safer pattern is to ask the reader to set an environment variable once, then use the variable everywhere:

code
export API_TOKEN="paste-your-token-here"
curl -H "Authorization: Bearer ${API_TOKEN:?set API_TOKEN first}" https://api.example.com/v1/me

The ${API_TOKEN:?message} form makes the shell stop with that message if the variable is empty or unset, instead of sending a request with a blank token. The placeholder is now in exactly one place, it is obviously a placeholder, and forgetting to fill it in produces a clear error rather than a confusing one.

Break long commands carefully

Long commands are easier to read split across lines with a trailing backslash:

shell
curl --fail --silent --show-error \
  --header "Accept: application/json" \
  --output result.json \
  https://api.example.com/v1/items

The backslash must be the very last character on the line. A single space after it changes its meaning: the backslash now escapes the space instead of the line break, the command ends early, and the next line runs as a separate command. That kind of trailing space is invisible on the page, so check for it in your draft.

Prefer long option names such as --silent over -s in tutorials. They are longer, but a reader can understand them without opening the manual, and they make the command easier to search for.

Watch for characters that only look right

Text editors and publishing tools like to improve punctuation. Straight quotes become curly quotes, two hyphens become a dash, and a space before a unit becomes a non-breaking space. In prose that is harmless. Inside a command it changes the command: a shell does not treat “ as a quote, and a program receiving an en dash instead of -- sees a different argument.

Always write code inside a proper code element, never as ordinary paragraph text, so the formatting tools leave it alone. Then check your draft for anything outside printable ASCII. Paste the commands from the post into a file and run:

code
LC_ALL=C grep -n '[^ -~]' commands.txt

This prints every line that contains a character outside the range from space to tilde, which catches curly quotes, dashes, non-breaking spaces and tabs. Some of those may be intended, such as tabs in a Makefile or accented text in a comment, but you will know at once which lines to look at.

Write files with a heredoc, and mark what is risky

When a step creates a configuration file, give the reader one command that writes the whole file, instead of “open an editor and type this”. A heredoc with a quoted delimiter does it without the shell touching the contents:

code
cat > config.toml <<'EOF'
[server]
port = 8080
log_level = "info"
EOF

Because 'EOF' is quoted, any $ or backtick inside the file is written literally rather than expanded. The > replaces the file if it already exists, which is worth saying in the sentence before the block.

The same applies to anything that deletes, overwrites or needs sudo: say what it does before the reader reaches it, as the publishing guidelines ask. On TechDug, wide blocks scroll sideways instead of wrapping, and readers with JavaScript on get a copy button on every block, as listed on the features page. That button copies exactly what is in the block, so the block has to be right. For the bigger picture of testing a whole tutorial end to end, see How to write a tutorial someone else can reproduce.

Written by

TechDug Editors

The house journal of TechDug. Notes from the editors on writing technical posts that work: reproducible steps, copyable commands, clear error write-ups and honest updates.

Comments 0

Comments are reviewed before they appear. Oldest first.

No comments yet. Spotted a typo, a better flag, or a step that failed for you? Say so below.

Add a comment

Just a name, no account and no email. A moderator reads every comment first.

Plain text, up to 2,000 characters.