(B)0[1;48r[m[?7h[?1h=[H[J[45B[0;7mGetting file://localhost/sdf/ftp/pub/users/paulr/technical-notes/unix-ed-indent.html[m[1;123HUNIX-ED-INDENT(7) -- Indentation Reset on Unix Using ed(1) (p1 of 2)[2;4Hpaulr.sdf.org BSD Unix Laboratory Report UNIX-ED-INDENT(7)[4;93H[0;1mTitle[2B[94DWhitespace Normalization on BSD Unix: Collapsing Runs and Resetting Indentation Using ed(1) and Standard Utilities[8;92HAbstract[2B[96D[mWe fix whitespace and indentation problems manually using standard Unix utilities, learning each tool as we go. Two tasks are covered: collapsing runs of whitespace into a single [1B space, and resetting drifted indentation in text and HTML files back to a clean baseline. The tools are ed(1), sed(1), tr(1), awk(1), and expand(1) -- all present on any Unix or BSD ntal text-processing operation in Unix system administration, source code maintenance, and document preparation. Two forms are routinely [1B required: [0;1mcollapsing[m, in which any run of one or more whitespace characters is replaced by a single space; and [0;1mindentation reset[m, in which the leading whitespace on each line is [1B stripped and optionally replaced with a canonical indent. [2B The BSD base system provides four tools suited to these operations without any package installation: [0;1med(1)[m, the original Unix line editor; [0;1msed(1)[m, the stream editor; [0;1mtr(1)[m, the [1B character translator; and [0;1mawk(1)[m, the pattern-scanning language. Each operates differently on whitespace, and the correct choice depends on whether line boundaries must be crossed, [1B whether the edit must be in-place, and whether POSIX portability is required [1]. ed by automated tools or pasted between editors. Indentation drifts when lines [1B are added interactively in ed(1) without awareness of the current nesting level. The standard POSIX character class [[:space:]] covers the full set of whitespace characters: [1B horizontal tab (HT), vertical tab (VT), form feed (FF), carriage return (CR), and space (SP) [2]. This experiment quantifies each tool's effectiveness for both normalization tasks.[28;83H[0;1mII. Materials and Methods [2B[mA. Equipment [2B BSD Unix System -- FreeBSD 14.0-RELEASE[33;11HBase system only; no ports or packages installed beyond the default distribution. Shell: /bin/sh (POSIX sh, ash-derived). All commands invoked from a login shell over SSH or[34;11Hat the console. ed; present on all BSD and Linux systems. [2B sed(1) -- BSD stream editor[41;11HReads input line by line, applies substitution expressions, writes to stdout. The -i '' flag (BSD sed) enables in-place editing by creating a temporary file and renaming it. [2B tr(1) -- character translator[44;11HMaps characters at the byte-stream level; uniquely able to process newline characters without line-at-a-time restrictions. The -s flag squeezes repeated characters in the[45;11Houtput class to a single instance, making it the natural tool for collapsing runs. [1B[H[188C6 [45B[1B Arrow keys: Up and Down to move. Right to follow a link; Left to go back. [1B H)elp O)ptions P)rint G)o M)ain screen Q)uit /=search [delete]=history list [2A[0;7m-- press space for next page --[m[K[H[183C2 e using the output field[5;11Hseparator (OFS, default single space), collapsing all inter-field whitespace. [1B[K[1B expand(1) / unexpand(1)[8;11HConvert between tab characters and space sequences. expand -t 4 replaces each tab with four spaces; unexpand -t 4 reverses the operation. Required as a pre-processing step[9;11Hwhen input files use mixed tab/space indentation. [1B[K[1B cat(1) with -A flag (GNU) / -e -t flags (BSD)[K [1B Reveals invisible whitespace characters: BSD cat -e marks line endings with $; cat -t renders tab characters as ^I. Used to verify input file whitespace composition before[13;11Hnormalization. [1B[K[1B Test Files [1B Three plain-text and HTML source files of 20-80 lines each, constructed to contain representative mixtures of tabs, multiple spaces, carriage returns, and inconsistent [1B indentation depth.[K [1B[K[1BB. Procedure -- Whitespace Collapsing Output was captured to a second file and diffed against the expected result (every run of whitespace replaced by [1B exactly one space, count not preserved).[K [2B 1. Inspect the file for whitespace composition[K [1B[K[1B Before editing, identify what kinds of whitespace are present. On BSD, cat -e marks line endings and cat -t shows tabs:[K [1B cat -e file.txt # $ marks every line ending; \r\n appears as ^M$ [1B cat -t file.txt # ^I marks tab characters[K [2B 2. Collapse using tr(1) -- recommended for cross-line whitespace [2B tr -s squeezes; the POSIX class [:space:] covers all whitespace including newlines: [1B tr -s '[:space:]' ' ' < file.txt > collapsed.txt[K [1B[K[1B Note: this flattens the entire file to one line if newlines are present. To collapse only horizontal whitespace while preserving line structure, restrict the class: [1B tr -s '[:blank:]' ' ' < file.txt > collapsed.txt through unchanged. [2B 3. Collapse using ed(1) -- in-place, no temp file [1B[K[1B The ed(1) substitution operates line-at-a-time, so newlines are not visible to it. This collapses horizontal whitespace runs within each line and writes back to the original file: [1B ed -s file.txt <<'EOF' [1B ,s/[[:space:]][[:space:]]*/ /g[K [1B w[K [1;48r[1;184H3 [1B q[1BEOF[K [1B[K[1B The pattern [[:space:]][[:space:]]* is POSIX BRE for "one or more whitespace characters" (equivalent to [[:space:]]+ in ERE). Each matching run is replaced by a single space. [2B 4. Collapse using sed(1) -- stdout [1B[K[1B sed 's/[[:space:]][[:space:]]*/ /g' file.txt [2B For BSD in-place editing, add -i '': [1B sed -i '' 's/[[:space:]][[:space:]]*/ /g' file.txt[K [1B[K[1B 5. Collapse using awk(1) -- field-level [1B[K[1B Forcing awk to rebuild each record collapses all inter-field whitespace. Leading and trailing whitespace is also stripped by default field-splitting: [1B awk '{$1=$1; print}' file.txt [2BC[19;17HIndentation Reset in ed(1) [2B When editing HTML interactively in ed(1), indentation drifts because ed has no awareness of document structure. The following procedure restores a clean indent baseline. All .[2B[61DCheck current indentation state [2B Print a range of lines with line numbers to see the current indent:[K [1B 1,20n <- print lines 1-20 with line numbers [1B .n <- print the current line with its number [1B .p[29;18H<- print the current line without its number [1B[K[1B 2. Strip all leading whitespace from every line [1B[K[1B The anchor ^ matches the start of each line; the class [[:space:]]* matches zero or more whitespace characters; replacing with nothing removes it: [1B ,s/^[[:space:]]*//[K [1B[K[1B After this command all lines are flush left. This is the reset. Write if satisfied: [3B 3. Apply a uniform indent to all lines [2B Prepend two spaces to every line: [1B ,s/^/ / [2B Prepend one tab to every line: [1B ,s/^//[7C<- the replacement contains a literal tab character [1B[48;78H[46;32H[H[183C4 [1B[K[1B 4. Indent or de-indent a specific range 5:[K [1B 10,25s/^/ / [1B[K[1B Remove exactly four spaces of leading indent from lines 10 through 25: [1B 10,25s/^ // [2B Remove any amount of leading whitespace from lines 10 through 25: [1B 10,25s/^[[:space:]]*// [2B[48DResolve mixed tabs and spaces before resetting [2B If the file contains mixed tab/space indentation, normalize to spaces first. From inside an ed session, the ! command runs a shell command and reloads the result: [1B w <- save current buffer first [1B ,d[18;31H<- delete all lines [1B r !expand -t 4 file.txt <- read back with tabs expanded to 4 spaces [2B Then proceed with ,s/^[[:space:]]*// to reset.[K [1B[K[1B 6. Undo [1B[K[1B ed(1) supports a single level of undo with the u command. It reverses the most recent command that modified the buffer. There is no multi-level undo; if multiple commands have been the last saved version: [1B u [27;21Hundo the most recent buffer change [1B q [28;21Hquit without writing (ed prompts if unsaved changes exist) [1B Q [29;21Hquit unconditionally, discarding all unsaved changes [2B NOTE: ed(1) will print a ? and refuse to quit with q if the buffer has unsaved changes. Type q a second time to force quit, or use Q. Neither q nor Q writes the file; only w[1B[173Ddoes. [1B[K[34;89H[1K [0;1mIII. Results[2B[98D[mTable I summarizes the behavior of each tool across both normalization tasks. Input files contained spaces, horizontal tabs, and in some tests carriage returns (\r). [1B Table I. Tool comparison for whitespace collapse and indentation reset. [2B [0;1mTool Collapses runs Crosses newlines In-place Strips leading WS POSIX[1B[97D[mtr -s '[:blank:]'[0;1m [mYes[0;1m [mNo[0;1m [mNo[0;1m [mNo[0;1m [mYes [mYes[0;1m [mYes[0;1m [mNo[0;1m [mNo[0;1m [mYes [1B sed s/[[:space:]][[:space:]]*/[0;1m [mYes[0;1m [mNo[0;1m [mBSD: -i ''[0;1m [mNo[0;1m [mYes [1B awk $1=$1[0;1m [mYes[0;1m [mNo[0;1m [mNo[0;1m [mYes (side effect)[0;1m [mYes [1B ed ,s/[[:space:]][[:space:]]*/[0;1m [mYes[0;1m [mNo[0;1m [mYes[0;1m [mNo[0;1m [mYes [1B ed ,s/^[[:space:]]*/[0;1m [mNo[0;1m [mNo[0;1m [mYes[0;1m [mYes[0;1m [mYes [1B[48;78H[46;32H[H[183C5 [2B Table II shows the key ed(1) indentation commands as a quick reference. All are typed at the * prompt inside an active ed session. [1B Table II. ed(1) indentation reset command reference. d Effect Scope[1B[80D[m,s/^[[:space:]]*/[0;1m [mStrip all leading whitespace[0;1m [mAll lines [1B ,s/^/ /[0;1m [mPrepend two spaces[0;1m [mAll lines [1B n,ms/^/ /[0;1m [mPrepend four spaces (indent one level)[0;1m [mLines n through m [1B n,ms/^ //[0;1m [mRemove four leading spaces (de-indent one level)[0;1m [mLines n through m [1B n,ms/^[[:space:]]*/[0;1m [mStrip all leading whitespace[0;1m [mLines n through m [1B 1,20n[0;1m [mPrint lines 1-20 with line numbers[0;1m [mLines 1 through 20 [1B .n[0;1m [mPrint current line with its number[0;1m [mCurrent line [1B u[0;1m [mUndo most recent buffer change[0;1m [mOne level only ithout saving (discard all changes)[0;1m [mEntire session [1B[K[1B Before/after example. Input line with mixed indentation: [1B BEFORE: "
Hello world.
" [1B (tab + 2 spaces before; 4 spaces between words) [1B AFTER strip+collapse: [1B step 1 expand -t 4 -> "
Hello world.
"[1B[56Dstep 2 ,s/^[[:space:]]*/ -> "Hello world.
" [1B step 3 ,s/[[:space:]][[:space:]]*/ /g -> "Hello world.
"[25;88H[1K [0;1mIV. Discussion[m[K [1B[K[1B The choice of tool depends on a single primary question: must the operation cross line boundaries? If the answer is yes -- for example, collapsing a paragraph that was broken across [1B lines with a hard newline -- only tr with [:space:] handles it directly in a single expression. All other tools are line-at-a-time and require a join step first. [1B[K[1BA. Why ed for In-Place Editing riginal, and renames the temporary to the original name. This breaks hard links, resets the inode, and is not [1B POSIX-specified. ed writes directly to the original inode via w: the file's inode number, hard link count, and permissions are unchanged. For files under version control or with [1B known inode references, ed is the safer choice [3].[K [2BB. The awk Field-Collapse Side Effect[K [1B[K[1B awk '{$1=$1; print}' strips leading and trailing whitespace as a side effect of field splitting, then rebuilds the record using OFS (a single space by default). This is convenient [1B but potentially destructive: it collapses whitespace inside quoted strings and HTML attribute values. Use it only on plain prose, not on structured markup. [1B[K[1BC. Indentation in HTML Edited with ed[K [1B[K[1B When composing or editing HTML in ed(1), the editor provides no structural awareness -- there is no auto-indent, no bracket matching, no tree view. Indentation is the editor's only to nesting depth. It drifts for two common reasons: [1B * The a (append) and i (insert) commands enter text verbatim; the user must type leading spaces manually on each line. [1B[48;78H[46;32H[H[183C6[1B[179D* Pasting pre-indented content from another source introduces a different indent convention (tabs vs. spaces, 2 vs. 4 spaces). [1B[K[1B The two-command reset sequence is the practical solution: strip all leading whitespace first (,s/^[[:space:]]*/), confirm the result with 1,20n, then re-apply a uniform indent to [1B the desired range. Because ed supports one level of undo, the strip step can be reversed immediately with u if the result is wrong. [1B[K[1B [0;1mWARNING.[m The substitution ,s/^[[:space:]]*/ is destructive across the entire file. Always write a backup first: w backup.html before running any global substitution. The u [1B command only undoes the single most recent change; it cannot recover from a sequence of edits. [1BD. Handling Mixed Tab and Space Indentation[K [1B[K[1B BSD cat -t reveals tab characters as ^I. If both tabs and spaces appear as indent, normalize to spaces before resetting. The recommended sequence from the shell: [1B expand -t 4 file.html | sed 's/^[[:space:]]*//' > clean.html [1B[K[1B Or entirely within an ed session (write first, then reload via the shell escape): [1B w[1B,d[K[1Br !expand -t 4 file.html [1B[K[1B After reloading, all leading whitespace is spaces and the reset commands apply uniformly. [1B[K[22;88H[1K [0;1mV. Conclusion [1B[m[K[1B On a BSD Unix base system, tr -s '[:blank:]' ' ' is the most concise expression for collapsing horizontal whitespace runs while preserving line structure. tr -s '[:space:]' ' ' [1B extends this across newlines at the cost of flattening the file to a single line. For in-place normalization that preserves inode identity, the ed(1) global substitution / /g followed by w is the correct POSIX-portable approach. [1B[K[1B For indentation reset when editing HTML in ed(1), the sequence to type is: ,s/^[[:space:]]*/ to strip all leading whitespace on every line, then n,ms/^/ / to re-apply a [1B four-space indent to the desired range. Use 1,20n at any point to inspect line numbers and current indentation state. If mixed tabs and spaces are present, run expand -t 4 before [1B any indent operation. [1B[25D________________________________________________________________________________________________________________________________________________________________________________ [1B[K[33;90H[1K [0;1mReferences[m[K [1B[K[1B 1. The Open Group. [0;1mThe Single UNIX Specification, Version 4 (POSIX.1-2017).[m IEEE Std 1003.1-2017. https://pubs.opengroup.org/onlinepubs/9699919799/ SIX Character Classes.[1B[156D3. B. W. Kernighan and R. Pike. [0;1mThe Unix Programming Environment.[m Englewood Cliffs, NJ: Prentice-Hall, 1984, pp. 73-104. [1B 4. D. Dougherty and A. Robbins. [0;1msed & awk,[m 2nd ed. Sebastopol, CA: O'Reilly Media, 1997.[K [1B 5. FreeBSD Project. [0;1mFreeBSD 14.0 Base System Manual Pages: ed(1), sed(1), tr(1), awk(1), expand(1).[m https://www.freebsd.org/cgi/man.cgi [2B BSD Unix -- Text Processing UNIX-ED-INDENT(7) Rev. 1.0 -- 2026 [2B Lynx compatible.[K [1B[K[1B[K[48;78H [2A[0;7mCommands: Use arrow keys to move, '?' for help, 'q' to quit, '<-' to go back.[m [0;7mYou are already at the end of this document.[m [46;45H[48;78H [2A[0;7mCommands: Use arrow keys to move, '?' for help, 'q' to quit, '<-' to go back.[m [0;7mAre you sure you want to quit? (y) [m[K [2B[J[48;1H aulr/technical-notes/unix-ed-indent.html[m[1;123HUNIX-ED-INDENT(7) -- Indentation Reset on Unix Using ed(1) (p1 of 2)[2;4Hpaulr.sdf.org BSD Unix Laboratory Report UNIX-ED-INDENT(7)[4;93H[0;1mTitle[2B[94DWhitespace Normalization on BSD Unix: Collapsing Runs and Resetting Indentation Using ed(1) and Standard Utilities[8;92HAbstract[2B[96D[mWe fix whitespace and indentation problems manually using standard Unix utilities, learning each tool as we go. Two tasks are covered: collapsing runs of whitespace into a single [1B space, and resetting drifted indentation in text and HTML files back to a clean baseline. The tools are ed(1), sed(1), tr(1), awk(1), and expand(1) -- all present on any Unix or BSD document preparation. Two forms are routinely [1B required: [0;1mcollapsing[m, in which any run of one or more whitespace characters is replaced by a single space; and [0;1mindentation reset[m, in which the leading whitespace on each line is [1B stripped and optionally replaced with a canonical indent. [2B The BSD base system provides four tools suited to these operations without any package installation: [0;1med(1)[m, the original Unix line editor; [0;1msed(1)[m, the stream editor; [0;1mtr(1)[m, the [1B character translator; and [0;1mawk(1)[m, the pattern-scanning language. Each operates differently on whitespace, and the correct choice depends on whether line boundaries must be crossed, [1B whether the edit must be in-place, and whether POSIX portability is required [1]. [2B HTML source files are a common target for both operations. Whitespace collapses when files are processed by automated tools or pasted between editors. Indentation drifts when lines dded interactively in ed(1) without awareness of the current nesting level. The standard POSIX character class [[:space:]] covers the full set of whitespace characters: [1B horizontal tab (HT), vertical tab (VT), form feed (FF), carriage return (CR), and space (SP) [2]. This experiment quantifies each tool's effectiveness for both normalization tasks.[28;83H[0;1mII. Materials and Methods [2B[mA. Equipment [2B BSD Unix System -- FreeBSD 14.0-RELEASE[33;11HBase system only; no ports or packages installed beyond the default distribution. Shell: /bin/sh (POSIX sh, ash-derived). All commands invoked from a login shell over SSH or[34;11Hat the console. [2B ed(1) -- BSD ed, POSIX line editor[37;11HThe standard line-oriented text editor. Accepts commands from stdin or a here-document. Operates on an in-memory buffer; the w command writes back to the original file[38;11Hwithout a temporary file. POSIX-specified; present on all BSD and Linux systems. nput line by line, applies substitution expressions, writes to stdout. The -i '' flag (BSD sed) enables in-place editing by creating a temporary file and renaming it. [2B tr(1) -- character translator[44;11HMaps characters at the byte-stream level; uniquely able to process newline characters without line-at-a-time restrictions. The -s flag squeezes repeated characters in the[45;11Houtput class to a single instance, making it the natural tool for collapsing runs. [1B[H[188C6 [45B[1B Arrow keys: Up and Down to move. Right to follow a link; Left to go back. [1B H)elp O)ptions P)rint G)o M)ain screen Q)uit /=search [delete]=history list [2A[0;7m-- press space for next page --[m[K[H[183C2 field whitespace. [1B[K[1B expand(1) / unexpand(1)[8;11HConvert between tab characters and space sequences. expand -t 4 replaces each tab with four spaces; unexpand -t 4 reverses the operation. Required as a pre-processing step[9;11Hwhen input files use mixed tab/space indentation. [1B[K[1B cat(1) with -A flag (GNU) / -e -t flags (BSD)[K [1B Reveals invisible whitespace characters: BSD cat -e marks line endings with $; cat -t renders tab characters as ^I. Used to verify input file whitespace composition before[13;11Hnormalization. [1B[K[1B Test Files [1B Three plain-text and HTML source files of 20-80 lines each, constructed to contain representative mixtures of tabs, multiple spaces, carriage returns, and inconsistent [1B indentation depth.[K [1B[K[1BB. Procedure -- Whitespace Collapsing hitespace replaced by [1B exactly one space, count not preserved).[K [2B 1. Inspect the file for whitespace composition[K [1B[K[1B Before editing, identify what kinds of whitespace are present. On BSD, cat -e marks line endings and cat -t shows tabs:[K [1B cat -e file.txt # $ marks every line ending; \r\n appears as ^M$ [1B cat -t file.txt # ^I marks tab characters[K [2B 2. Collapse using tr(1) -- recommended for cross-line whitespace [2B tr -s squeezes; the POSIX class [:space:] covers all whitespace including newlines: [1B tr -s '[:space:]' ' ' < file.txt > collapsed.txt[K [1B[K[1B Note: this flattens the entire file to one line if newlines are present. To collapse only horizontal whitespace while preserving line structure, restrict the class: [1B tr -s '[:blank:]' ' ' < file.txt > collapsed.txt [1B[K[1B [:blank:] covers space and horizontal tab only; newlines are passed through unchanged. [2B 3. Collapse using ed(1) -- in-place, no temp file The ed(1) substitution operates line-at-a-time, so newlines are not visible to it. This collapses horizontal whitespace runs within each line and writes back to the original file: [1B ed -s file.txt <<'EOF' [1B ,s/[[:space:]][[:space:]]*/ /g[K [1B w[K [1;48r[1;184H3 [1B q[1BEOF[K [1B[K[1B The pattern [[:space:]][[:space:]]* is POSIX BRE for "one or more whitespace characters" (equivalent to [[:space:]]+ in ERE). Each matching run is replaced by a single space. [2B 4. Collapse using sed(1) -- stdout [1B[K[1B sed 's/[[:space:]][[:space:]]*/ /g' file.txt [2B For BSD in-place editing, add -i '': [1B sed -i '' 's/[[:space:]][[:space:]]*/ /g' file.txt[K [1B[K[1B 5. Collapse using awk(1) -- field-level [1B[K[1B Forcing awk to rebuild each record collapses all inter-field whitespace. Leading and trailing whitespace is also stripped by default field-splitting: [1B awk '{$1=$1; print}' file.txt [2BC[19;17HIndentation Reset in ed(1) [2B When editing HTML interactively in ed(1), indentation drifts because ed has no awareness of document structure. The following procedure restores a clean indent baseline. All .[2B[61DCheck current indentation state [2B Print a range of lines with line numbers to see the current indent:[K [1B 1,20n <- print lines 1-20 with line numbers [1B .n <- print the current line with its number [1B .p[29;18H<- print the current line without its number [1B[K[1B 2. Strip all leading whitespace from every line [1B[K[1B The anchor ^ matches the start of each line; the class [[:space:]]* matches zero or more whitespace characters; replacing with nothing removes it: [1B ,s/^[[:space:]]*//[K [1B[K[1B After this command all lines are flush left. This is the reset. Write if satisfied: [3B 3. Apply a uniform indent to all lines [2B Prepend two spaces to every line: [1B ,s/^/ / [2B Prepend one tab to every line: [1B ,s/^//[7C<- the replacement contains a literal tab character [1B[48;78H[46;32H[H[183C4 [1B[K[1B 4. Indent or de-indent a specific range 5:[K [1B 10,25s/^/ / [1B[K[1B Remove exactly four spaces of leading indent from lines 10 through 25: [1B 10,25s/^ // [2B Remove any amount of leading whitespace from lines 10 through 25: [1B 10,25s/^[[:space:]]*// [2B[48DResolve mixed tabs and spaces before resetting [2B If the file contains mixed tab/space indentation, normalize to spaces first. From inside an ed session, the ! command runs a shell command and reloads the result: [1B w <- save current buffer first [1B ,d[18;31H<- delete all lines [1B r !expand -t 4 file.txt <- read back with tabs expanded to 4 spaces [2B Then proceed with ,s/^[[:space:]]*// to reset.[K [1B[K[1B 6. Undo [1B[K[1B ed(1) supports a single level of undo with the u command. It reverses the most recent command that modified the buffer. There is no multi-level undo; if multiple commands have been the last saved version: [1B u [27;21Hundo the most recent buffer change [1B q [28;21Hquit without writing (ed prompts if unsaved changes exist) [1B Q [29;21Hquit unconditionally, discarding all unsaved changes [2B NOTE: ed(1) will print a ? and refuse to quit with q if the buffer has unsaved changes. Type q a second time to force quit, or use Q. Neither q nor Q writes the file; only w[1B[173Ddoes. [1B[K[34;89H[1K [0;1mIII. Results[2B[98D[mTable I summarizes the behavior of each tool across both normalization tasks. Input files contained spaces, horizontal tabs, and in some tests carriage returns (\r). [1B Table I. Tool comparison for whitespace collapse and indentation reset. [2B [0;1mTool Collapses runs Crosses newlines In-place Strips leading WS POSIX[1B[97D[mtr -s '[:blank:]'[0;1m [mYes[0;1m [mNo[0;1m [mNo[0;1m [mNo[0;1m [mYes [mYes[0;1m [mYes[0;1m [mNo[0;1m [mNo[0;1m [mYes [1B sed s/[[:space:]][[:space:]]*/[0;1m [mYes[0;1m [mNo[0;1m [mBSD: -i ''[0;1m [mNo[0;1m [mYes [1B awk $1=$1[0;1m [mYes[0;1m [mNo[0;1m [mNo[0;1m [mYes (side effect)[0;1m [mYes [1B ed ,s/[[:space:]][[:space:]]*/[0;1m [mYes[0;1m [mNo[0;1m [mYes[0;1m [mNo[0;1m [mYes [1B ed ,s/^[[:space:]]*/[0;1m [mNo[0;1m [mNo[0;1m [mYes[0;1m [mYes[0;1m [mYes [1B[48;78H[46;32H[H[183C5 [2B Table II shows the key ed(1) indentation commands as a quick reference. All are typed at the * prompt inside an active ed session. [1B Table II. ed(1) indentation reset command reference. d Effect Scope[1B[80D[m,s/^[[:space:]]*/[0;1m [mStrip all leading whitespace[0;1m [mAll lines [1B ,s/^/ /[0;1m [mPrepend two spaces[0;1m [mAll lines [1B n,ms/^/ /[0;1m [mPrepend four spaces (indent one level)[0;1m [mLines n through m [1B n,ms/^ //[0;1m [mRemove four leading spaces (de-indent one level)[0;1m [mLines n through m [1B n,ms/^[[:space:]]*/[0;1m [mStrip all leading whitespace[0;1m [mLines n through m [1B 1,20n[0;1m [mPrint lines 1-20 with line numbers[0;1m [mLines 1 through 20 [1B .n[0;1m [mPrint current line with its number[0;1m [mCurrent line [1B u[0;1m [mUndo most recent buffer change[0;1m [mOne level only ithout saving (discard all changes)[0;1m [mEntire session [1B[K[1B Before/after example. Input line with mixed indentation: [1B BEFORE: "Hello world.
" [1B (tab + 2 spaces before; 4 spaces between words) [1B AFTER strip+collapse: [1B step 1 expand -t 4 -> "
Hello world.
"[1B[56Dstep 2 ,s/^[[:space:]]*/ -> "Hello world.
" [1B step 3 ,s/[[:space:]][[:space:]]*/ /g -> "Hello world.
"[25;88H[1K [0;1mIV. Discussion[m[K [1B[K[1B The choice of tool depends on a single primary question: must the operation cross line boundaries? If the answer is yes -- for example, collapsing a paragraph that was broken across [1B lines with a hard newline -- only tr with [:space:] handles it directly in a single expression. All other tools are line-at-a-time and require a join step first. [1B[K[1BA. Why ed for In-Place Editing riginal, and renames the temporary to the original name. This breaks hard links, resets the inode, and is not [1B POSIX-specified. ed writes directly to the original inode via w: the file's inode number, hard link count, and permissions are unchanged. For files under version control or with [1B known inode references, ed is the safer choice [3].[K [2BB. The awk Field-Collapse Side Effect[K [1B[K[1B awk '{$1=$1; print}' strips leading and trailing whitespace as a side effect of field splitting, then rebuilds the record using OFS (a single space by default). This is convenient [1B but potentially destructive: it collapses whitespace inside quoted strings and HTML attribute values. Use it only on plain prose, not on structured markup. [1B[K[1BC. Indentation in HTML Edited with ed[K [1B[K[1B When composing or editing HTML in ed(1), the editor provides no structural awareness -- there is no auto-indent, no bracket matching, no tree view. Indentation is the editor's only to nesting depth. It drifts for two common reasons: [1B * The a (append) and i (insert) commands enter text verbatim; the user must type leading spaces manually on each line. [1B[48;78H[46;32H[H[183C6[1B[179D* Pasting pre-indented content from another source introduces a different indent convention (tabs vs. spaces, 2 vs. 4 spaces). [1B[K[1B The two-command reset sequence is the practical solution: strip all leading whitespace first (,s/^[[:space:]]*/), confirm the result with 1,20n, then re-apply a uniform indent to [1B the desired range. Because ed supports one level of undo, the strip step can be reversed immediately with u if the result is wrong. [1B[K[1B [0;1mWARNING.[m The substitution ,s/^[[:space:]]*/ is destructive across the entire file. Always write a backup first: w backup.html before running any global substitution. The u [1B command only undoes the single most recent change; it cannot recover from a sequence of edits. [1BD. Handling Mixed Tab and Space Indentation[K [1B[K[1B BSD cat -t reveals tab characters as ^I. If both tabs and spaces appear as indent, normalize to spaces before resetting. The recommended sequence from the shell: [1B expand -t 4 file.html | sed 's/^[[:space:]]*//' > clean.html [1B[K[1B Or entirely within an ed session (write first, then reload via the shell escape): [1B w[1B,d[K[1Br !expand -t 4 file.html [1B[K[1B After reloading, all leading whitespace is spaces and the reset commands apply uniformly. [1B[K[22;88H[1K [0;1mV. Conclusion [1B[m[K[1B On a BSD Unix base system, tr -s '[:blank:]' ' ' is the most concise expression for collapsing horizontal whitespace runs while preserving line structure. tr -s '[:space:]' ' ' [1B extends this across newlines at the cost of flattening the file to a single line. For in-place normalization that preserves inode identity, the ed(1) global substitution / /g followed by w is the correct POSIX-portable approach. [1B[K[1B For indentation reset when editing HTML in ed(1), the sequence to type is: ,s/^[[:space:]]*/ to strip all leading whitespace on every line, then n,ms/^/ / to re-apply a [1B four-space indent to the desired range. Use 1,20n at any point to inspect line numbers and current indentation state. If mixed tabs and spaces are present, run expand -t 4 before [1B any indent operation. [1B[25D________________________________________________________________________________________________________________________________________________________________________________ [1B[K[33;90H[1K [0;1mReferences[m[K [1B[K[1B 1. The Open Group. [0;1mThe Single UNIX Specification, Version 4 (POSIX.1-2017).[m IEEE Std 1003.1-2017. https://pubs.opengroup.org/onlinepubs/9699919799/ SIX Character Classes.[1B[156D3. B. W. Kernighan and R. Pike. [0;1mThe Unix Programming Environment.[m Englewood Cliffs, NJ: Prentice-Hall, 1984, pp. 73-104. [1B 4. D. Dougherty and A. Robbins. [0;1msed & awk,[m 2nd ed. Sebastopol, CA: O'Reilly Media, 1997.[K [1B 5. FreeBSD Project. [0;1mFreeBSD 14.0 Base System Manual Pages: ed(1), sed(1), tr(1), awk(1), expand(1).[m https://www.freebsd.org/cgi/man.cgi [2B BSD Unix -- Text Processing UNIX-ED-INDENT(7) Rev. 1.0 -- 2026 [2B Lynx compatible.[K [1B[K[1B[K[48;78H [2A[0;7mCommands: Use arrow keys to move, '?' for help, 'q' to quit, '<-' to go back.[m [0;7mYou are already at the end of this document.[m [46;45H[48;78H [2A[0;7mCommands: Use arrow keys to move, '?' for help, 'q' to quit, '<-' to go back.[m[2B[2A[2B[2A [0;7mAre you sure you want to quit? (y) [m[K [2B[J[48;1H