sed
Stream EDitor

Lukáš Bařinka

sed
stream editor for filtering and transforming text


man -f sed

TOC

Obsah

  1. Syntax
  2. Commands
  3. Buffers
  4. Multiline
  5. Branching
  6. Debug
  7. GNU Extensions
  1. Syntaxe
  2. Příkazy
  3. Buffery (prostory)
  4. Multiline
  5. Větvení
  6. Ladění
  7. GNU rozšíření

SyntaxSyntaxe

Stream EDitor?

Sed idea

Syntax overviewPřehled syntaxe

sed [OPTION]… {script-only-if-no-other-script} [input-file]…

Sed start

OptionsPřepínače

-n
Suppress automatic printing of pattern space
-e script
Add the script to the commands to be executed
-f script-file
Add the contents of script-file to the commands to be executed
-i[SUFFIX]
Edit files in place (via temp file)Makes backup if SUFFIX supplied
-E, -r
Use extended regular expressions in the script For portability use POSIX -E
-n
Potlačuje implicitní tisk na výstup
-e script
Přidává část sed skriptu
-f script-file
Přidává obsah souboru jako sktript s příkazy, který se bude vykonávat
-i[SUFFIX]
Edituje soubor samotný (přes dočasný soubor) Vytváří zálohu podle přípony SUFFIX
-E, -r
Regulární výrazy budou považovány za rozšířené (ERE) Pro přenositelnost použijte POSIX -E

Script syntaxSyntaxe skriptu

Script syntax

CommandsPříkazy

Commands overviewPřehled příkazů

Commands overview

Basic commandsZákladní příkazy

#
comment until next new line
p
print P.B (pattern buffer)
d
delete P.B. + start next cycle
q
quit script (after print) [with exit code]
Q
quit script (before print) [with exit code]
{ CMD ; CMD ... }
group several commands together
s
substitute P.B.s/RE/text/flags
y
transliterate characters in P.B.y/src/dst/
#
komentář do konce řádku
p
výpis pattern bufferu (P.B.)
d
smazání P.B. + pokračování dálší řádkou
q
ukončení skriptu (po výpisu řádky) [s exit kódem]
Q
ukončení skriptu (před výpisem řádky) [s exit k.]
{ CMD ; CMD ... }
skupina příkazů
s
substituce P.B.s/RE/text/flags
y
záměna znaků v P.B.y/src/dst/

SubstitutionSubstituce

s/RE/text/flags

  • RE = (Extended) Regular Expression
  • text = replacement
    • & = matching pattern space
    • \1\9 = matching subexpression
    • \l, \L = convert to lowercase (first/all)
    • \u, \U = convert to uppercase (first/all)
    • \E = stop case conversion
  • RE = (rozšířený) regulární výraz
  • text = náhrada
    • & = odpovídající řetězec (pattern space)
    • \1\9 = odpovídající podvýraz
    • \l, \L = převod na malá písmena (první/vše)
    • \u, \U = převod na velká písmena (první/vše)
    • \E = konec konverze

							s/RE/text/
							s,RE,t/e/x/t,
							/RE/s//text/
							/RE/s///
						

							s/[[:digit:]]+/(&)/
							s/[[:digit:]]+/#&/
							s/([[:digit:]]*)\.?([[:digit:]]*)/int: \1, frac: \2/
							s/.*/L: \L&\E, U: \U&\E, orig: &/
						

FlagsPříznaky

g
global (replace all occurences)
globálně (nahradí všechny výskyty)
n
replace nth occurence
nahradí n-tý výskyt
p
print result when substitution was made
vypíše výsledek pokud náhrada proběhla
w FILE
write result to file when substitution was made
výsledek do souboru pokud náhrada proběhla
e
pipe input from a shell command into pattern space
spustí výsledek shellem a nahradí za výstup příkazu
   when substitution was made
   pokud náhrada proběhla
   sed 's/$/ +%T/e; s/:/|/g' <<<dateAnimation

Example - Exchange ratesUkázka - Kurzy ČNB


							#!/bin/sed -nf
							/<h3/ {
							  # Date and number of exchange rate
							  s/.*Platnost od //
							  s/P.*: /#/
							  s/<.*//
							 
							  # Another solution using subexpressions
							  #s/.*Platnost od \([^ ]*\) .*: \([0-9]\{1,\}\).*/\1 #\2/p
							}
							 
							...
						

							#!/bin/sed -nf
							/<h3/ {
							  # Datum a pořadí kurzovního lístku
							  s/.*Platnost od //
							  s/P.*: /#/
							  s/<.*//
							 
							  # Jinak, pomocí podvýrazů
							  #s/.*Platnost od \([^ ]*\) .*: \([0-9]\{1,\}\).*/\1 #\2/p
							}
							 
							...
						
Sed substitution - rate example


							<br class="noprint">
							<div class="highlighted" style="color:red; font-weight:bold;">Data pro aktuální pracovní den jsou k dispozici po 14:30</div><br>

							<h3 class="kurzy_tisk">Platnost od 24.03.2010 Pořadí: 58</h3>
							<table class="kurzy_tisk">
							<tr><th>země</th><th>měna</th><th>množství</th><th>kód</th><th>kurz</th></tr>
							<tr><td>Austrálie</td><td>dolar</td><td align="right">1</td><td>AUD</td><td align="right">17,313</td></tr><tr><td>Brazílie</td><td>real</td><td align="right">1</td><td>BRL</td><td align="right">10,621</td></tr><tr><td>Bulharsko</td><td>lev</td><td align="right">1</td><td>BGN</td><td align="right">12,976</td></tr><tr><td>Čína</td><td>renminbi</td><td align="right">1</td><td>CNY</td><td align="right">2,786</td></tr><tr><td>Dánsko</td><td>koruna</td><td align="right">1</td><td>DKK</td><td align="right">3,410</td></tr><tr><td>EMU</td><td>euro</td><td align="right">1</td><td>EUR</td><td align="right">25,375</td></tr><tr><td>Estonsko</td><td>koruna</td><td align="right">1</td><td>EEK</td><td align="right">1,622</td></tr><tr><td>Filipíny</td><td>peso</td><td align="right">100</td><td>PHP</td><td align="right">41,734</td></tr><tr><td>Hongkong</td><td>dolar</td><td align="right">1</td><td>HKD</td><td align="right">2,451</td></tr><tr><td>Chorvatsko</td><td>kuna</td><td align="right">1</td><td>HRK</td><td align="right">3,494</td></tr><tr><td>Indie</td><td>rupie</td><td align="right">100</td><td>INR</td><td align="right">41,826</td></tr><tr><td>Indonesie</td><td>rupie</td><td align="right">1000</td><td>IDR</td><td align="right">2,084</td></tr><tr><td>Japonsko</td><td>jen</td><td align="right">100</td><td>JPY</td><td align="right">20,692</td></tr><tr><td>Jihoafrická rep.</td><td>rand</td><td align="right">1</td><td>ZAR</td><td align="right">2,576</td></tr><tr><td>Jižní Korea</td><td>won</td><td align="right">100</td><td>KRW</td><td align="right">1,671</td></tr><tr><td>Kanada</td><td>dolar</td><td align="right">1</td><td>CAD</td><td align="right">18,590</td></tr><tr><td>Litva</td><td>litas</td><td align="right">1</td><td>LTL</td><td align="right">7,349</td></tr><tr><td>Lotyšsko</td><td>lat</td><td align="right">1</td><td>LVL</td><td align="right">35,845</td></tr><tr><td>Maďarsko</td><td>forint</td><td align="right">100</td><td>HUF</td><td align="right">9,611</td></tr><tr><td>Malajsie</td><td>ringgit</td><td align="right">1</td><td>MYR</td><td align="right">5,733</td></tr><tr><td>Mexiko</td><td>peso</td><td align="right">1</td><td>MXN</td><td align="right">1,518</td></tr><tr><td>MMF</td><td>SDR</td><td align="right">1</td><td>XDR</td><td align="right">28,830</td></tr><tr><td>Norsko</td><td>koruna</td><td align="right">1</td><td>NOK</td><td align="right">3,161</td></tr><tr><td>Nový Zéland</td><td>dolar</td><td align="right">1</td><td>NZD</td><td align="right">13,338</td></tr><tr><td>Polsko</td><td>zlotý</td><td align="right">1</td><td>PLN</td><td align="right">6,526</td></tr><tr><td>Rumunsko</td><td>nové leu</td><td align="right">1</td><td>RON</td><td align="right">6,237</td></tr><tr><td>Rusko</td><td>rubl</td><td align="right">100</td><td>RUB</td><td align="right">64,038</td></tr><tr><td>Singapur</td><td>dolar</td><td align="right">1</td><td>SGD</td><td align="right">13,538</td></tr><tr><td>Švédsko</td><td>koruna</td><td align="right">1</td><td>SEK</td><td align="right">2,618</td></tr><tr><td>Švýcarsko</td><td>frank</td><td align="right">1</td><td>CHF</td><td align="right">17,764</td></tr><tr><td>Thajsko</td><td>baht</td><td align="right">100</td><td>THB</td><td align="right">58,768</td></tr><tr><td>Turecko</td><td>nová lira</td><td align="right">1</td><td>TRY</td><td align="right">12,310</td></tr><tr><td>USA</td><td>dolar</td><td align="right">1</td><td>USD</td><td align="right">19,020</td></tr><tr><td>Velká Británie</td><td>libra</td><td align="right">1</td><td>GBP</td><td align="right">28,364</td></tr>
							</table>

						

							...
							/<table.*kurzy_tisk/,+2 {
							  s/<\/tr>/\n/g    # Rozdělit na řádky (multiline) ! GNU sed
							 
							  s/<\/t[hd]>/|/g  # Oddělit položky
							 
							  s/<[^>]*>//g     # Odstranit zbylé tagy
							 
							  s/|\n/\n/g       # Odstranit ukončení poslední položky
							 
							  s/\r//           # Odstranit (DOS) LF
							 
							  s/\n$//          # Odstranit odřádkování na koncích řádků původní tabulky
							 
							  /^$/!p           # Vypsat vše kromě prázdných řádků
							}
						

							...
							/<table.*kurzy_tisk/,+2 {
							  s/<\/tr>/\n/g    # Split into separate lines (multiline) ! GNU sed
							 
							  s/<\/t[hd]>/|/g  # Separate fields (table cells)
							 
							  s/<[^>]*>//g     # Remove remaining tags
							 
							  s/|\n/\n/g       # Remove trailing separator
							 
							  s/\r//           # Remove (DOS) LF
							 
							  s/\n$//          # Remove trailing newlines (of origin table)
							 
							  /^$/!p           # Print out everything except empty lines
							}
						

							URL='https://www.cnb.cz/en/financial-markets/foreign-exchange-market/central-bank-exchange-rate-fixing/central-bank-exchange-rate-fixing/'
							curl "$URL" 2>/dev/null | sed ... | diff - rates.txt
						

							URL='https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/index.html'
							curl "$URL" 2>/dev/null | sed ... | diff - rates.txt
						

Lines of TextŘádky textu

i TEXT
insert text
vloží řádku textu před řádek
a TEXT
append text
vloží řádku textu za řádek
c TEXT
change line with text
nahradí řádku za text
r FILE
read and print content of file
přečte/zapíše na výstup obsah souboru file
R FILE
read and print next line from file
načte/zapíše na výstup další řádku souboru file
w FILE
write P.B. into file
zapíše obsah P.B. do souboru file
W FILE
write first line of P.B. into file
zapíše první řádku P.B. do souboru file

ExamplesUkázky


							seq 3 | sed '2i text'

							seq 3 | sed '2i\
							text'

							seq 3 | sed -e '2i\' -e text
							seq 3 | sed -e '2i\' -e "$VAR"

							seq 3 | sed '2i\
							\text\
							foo'

							seq 3 | sed '2i\
							\\text\\'
						

							printf '%d %d %d\n' {1..15} \
							| sed -E '
							  1 i <table>
							    i <tr><td>
							    s_ +_</td><td>_g
							    a </td></tr>
							  $ a </table>
							'
						
info -n 'other commands' sed

Split text into filesRozdělení textu do souborů


							man -k print \
							| sed '
							    s_[^(]*(\([^)]*\)).*_\1_
							  ' \
							| sort -u \
							| sed '
							    1i #!/bin/sed -f
							    s_.*_/(&)/w &.man_
							  ' \
							> mansplit

							chmod +x mansplit
							man -k print | ./mansplit
						

							a2ps (1)             - format files for printing on a PostScript printer
							arch (1)             - print machine hardware name (same as uname -m)
							asprintf (3)         - print to allocated string
							B::Concise (3perl)   - Walk Perl syntax tree, printing concise info about ops
							B::Terse (3perl)     - Walk Perl syntax tree, printing terse info about ops
							bbox (1)             - prints out the bounding box of a rawppm or rawpbm image
							blkid (8)            - locate/print block device attributes
							card (1)             - print reference card of program options
							cat (1)              - concatenate files and print on the standard output
							cloudprint (1)       - share CUPS printers with Google Cloud Print
							cloudprint-service (7) - manage the Google Cloud Print proxy
							cloudprintd (1)      - share CUPS printers with Google Cloud Print
							cps-auth (1)         - Perform OAuth2 authentication for cloudprint-service
							cups (1)             - a standards-based, open source printing system
							cups-browsed (8)     - A daemon for browsing the Bonjour broadcasts of shared...
							cups-calibrate (8)   - ESP CUPS Printer Calibration Tool
							cups-genppdupdate (8) - update CUPS+Gutenprint PPD files
							cups-lpd (8)         - receive print jobs and report printer status to lpd cl...
							cupsdisable (8)      - stop/start printers and classes
							cupsenable (8)       - stop/start printers and classes
							Data::Dump (3pm)     - Pretty printing of data structures
							Data::Dump::Filtered (3pm) - Pretty printing with filtering
							Data::Dumper (3perl) - stringified perl data structures, suitable for both pr...
							date (1)             - print or set the system date and time
						

Next lineDalší řádka

n
next line
  • Print current P.B. (if not -n)
  • Replace P.B. with next line
  • Exit if no more input lines
n
další řádka
  • Vypíše obsah P.B. (pokud nebylo -n)
  • Nahradí P.B. další řádkou ze vstupu
  • Skončí, pokud není další řádka na vstupu

							printf '%d\n' {1..10} | sed 'n;d'
							1
							3
							5
							7
							9

							printf '%d\n' {1..10} | sed '1!n;d'
							2
							4
							6
							8
							10
						

Hold buffer (space)

Pattern and Hold bufferPattern a Hold buffer

Buffers in sed
  • Pattern Buffer content is overwritten by input line
  • Hold Buffer has stable content servers as variable (memory)
  • Substitutions and print-outs use Pattern Buffer only
  • Pattern Buffer je přepisován obsahem zpracovávané řádky
  • Hold Buffer má stabilní obsah slouží jako proměnná (paměť)
  • Změny obsahu a výpis probíhají pouze nad Pattern Bufferem

Hold Buffer

h / H
Replace/append contents of H.B. with P.B. Pattern Buffer ⇨ Hold Buffer
Nahradí/přidá obsah H.B. obsahem P.B. Pattern Buffer ⇨ Hold Buffer
g / G
Replace/append contents of P.B. with H.B. Hold Buffer ⇨ Pattern Buffer
Nahradí/přidá obsah P.B. obsahem H.B. Hold Buffer ⇨ Pattern Buffer
x
Exchange contents of H.B and P.B. Pattern Buffer Hold Buffer
Zamění obsahy H.B a P.B. Pattern Buffer Hold Buffer

Example (min:max)Ukázka (min:max)


							stat -c '%s' * \
							| sort -n \
							| sed -n '
							    # at the beginning - store min
							    1 h
							 
							    # at the end
							    $ {
							      # store \n + max
							      H
							 
							      # load min + \n + max
							      g
							 
							      # replace \n with :
							      s_\n_:_p
							    }'
						

							input    P.B.           H.B.
							 
							first
							first  → first
							first    first        → first
							...                     first
							...    → ...            first
							last                    first
							last   → last           first
							last     last         → first\nlast
							 
							 
							last     first\nlast ←  first\nlast
							 
							 
							last     first:last     first\nlast
							             ↓
						

Reverse lines (tac)Opačné pořadí řádek (tac)

Missing image: "images/tac.svg"

?


							seq 100 | sed -n 'H;g;1,9!s/[^\n]*\n//;h;$p'
						

							#!/bin/sed -n
							H
							g
							1,9! s/[^\n]*\n//
							h
							$ p
						

Multiline

New line (↵)Odřádkování (↵)

D
delete first line from pattern buffer and restart cycle
smaže 1. řádek z pattern bufferu a restartuje cyklus
N
append ↵ + next line from input into pattern buffer
přidá ↵ + další řádek ze vstupu do pattern bufferu
P
print first line from pattern buffer to output
vypíše první řádek z pattern bufferu na výstup
G
append ↵ + content of hold buffer into pattern buffer
přidá ↵ + obsah hold bufferu do pattern bufferu
H
append ↵ + content of pattern buffer into hold buffer
přidá ↵ + obsah pattern bufferu do hold bufferu


							seq 5 | sed -n 'N; h; s/\n/ - /p; g; D'
							1 - 2
							2 - 3
							3 - 4
							4 - 5
						

Multiline substitutionNáhrada ve víceřádkovém obsahu


							echo 1 2 3 4 5 6 7 8 9 10 | sed 's/ /\n/g; s/^/./gM ; P; D'
								.1
								..2
								...3
								....4
								.....5
								......6
								.......7
								........8
								.........9
								..........10
						

BranchingVětvení

CommandsPříkazy

d
Deletes P.B., and restarts the cycle
Smaže P.B. a restartuje cyklus
D
Deletes line from P.B. until first NL, and restarts the cycle
Smaže řádku z P.B. po první další NL a restartuje cyklus
ADDR commandpříkaz
ADDR { commandspříkazy }
Conditional command(s) execution (if-then)
Podmíněné spuštění příkazu(ů) (if-then)

CommandsPříkazy

: label
Label typically single letter
b [label]
Branch unconditionally (always jump) to label or to end
t [label]
Branch conditionally (test and jump) to label or to end Only if s/// command has succeeded
T [label]
Opposite of t command

Thousands separatorOddělovač tisíců


							echo 1234567890 | \
							sed -E \
							    -e :a \
							    -e 's/(.*[0-9])([0-9]{3})/\1,\2/' \
							    -e ta
						

							1,234,567,890
						

Joining linesSpojování řádků


							sed -e :a \
							    -e '/\\$/N' \
							    -e 's/\\\n//' \
							    -e ta
						

							sed ':x
							     /\\$/ {
							            N
							            s/\\\n//g
							            bx
							     }'
						

							a \
							b \
							c
							d \
							e
							f
						

							a b c
							d e
							f
						

Processing whole input at onceZpracování celého vstupu najednou


							printf "%s\n" {a..h} | \
							sed -n '
							        :a
							        $! { N; ba }
							        s/\n/:/gp
							       '
						

							a:b:c:d:e:f:g:h
						

Is that correct?Je to správně?


							#!/bin/sed -f
							/<!--/! b

							        :a

							 /-->/! {
							           N
							           ba
							        }

							        s/<!--.*-->//
						

								T1
							 
								T2 <!-- C1 --> T3
							 
								T4 <!-- C2
								C3 --> T5
							 
								T6 <!-- C4 --> T7 <!-- C5 --> T8
							
						

DebugLadění

OptionPřepínač

echo 1 | sed --debug '\%1%s21232'

  • SED PROGRAM: /1/ s/1/3/
  • INPUT: 'STDIN' line 1
  • PATTERN: 1
  • COMMAND: /1/ s/1/3/
  • PATTERN: 3
  • END-OF-CYCLE:
  • 3

							printf '%03d\n' {1..10} | sed --debug '/[02468]$/{N;s/\n/-/}'
						

CommandsPříkazy

=
Print current input line number
l
Print P.B. in unambiguous form l width - sets output width
=
Vypíše číslo aktuálního vstupního řádku
l
Vypíše obsah P.B. v čitelné podobě l width - nastaví šířku výpisu

							man sed | sed -n $=
						

							printf '%s\n' {1..5} | \
							sed '
							  :a
							  =
							  $! {
							      l
							      N
							      b a
							  }
							  l
							  s,\n,\t,g
							  l
							'
						

							1
							1$
							2
							1\n2$
							3
							1\n2\n3$
							4
							1\n2\n3\n4$
							5
							1\n2\n3\n4\n5$
							1\t2\t3\t4\t5$
							1      2      3      4      5
						

GNU ExtensionsGNU rozšíření

Case sensitivityVelikost znaků

  • Case-insensitive addressing
    sed -n /ROOT/Ip /etc/passwd
  • Case-insensitive substitution (search)
    sed s/foo/bar/I <<<FoO
  • Adresace bez ohledu na velikost písmen
    sed -n /ROOT/Ip /etc/passwd
  • Náhrada (hledání) bez ohledu na velikost písmen
    sed s/foo/bar/I <<<FoO

Regular expressionsRegulární výrazy

  • Sub-expressions repetition E.g. login shell in pattern /x/y sed -En '\_:(/[^:/]+){2}$_p' /etc/passwd
  • RE addresses choice (RE1|RE2)
    sed -n '/^\(root\|uucp\):/p' /etc/passwd sed -En '/^(root|uucp):/p' /etc/passwd
  • Character classes
    man man | sed '/^[[:blank:]]*$/d' man man | sed '/^\s*$/d'
  • Opakování podvýrazů Např. login shell ve tvaru /x/y sed -En '\_:(/[^:/]+){2}$_p' /etc/passwd
  • Výběr mezi RE adresami (RE1|RE2)
    sed -n '/^\(root\|uucp\):/p' /etc/passwd sed -En '/^(root|uucp):/p' /etc/passwd
  • Třídy znaků
    man man | sed '/^[[:blank:]]*$/d' man man | sed '/^\s*$/d'

Extended addressingRozšířená adresace

FIRST~STEP
FIRST + (N * STEP)

								seq 10 | sed -n 0~2p # even
								seq 10 | sed -n 1~2p # odd
							
0,/RE/
Try to match RE in the first input line too
ADDR1,+N
Matches ADDR1 and the N lines following ADDR1
ADDR1,~N
Matches ADDR1 and the lines following ADDR1 until the next line modulo N
FIRST~STEP
FIRST + (N * STEP)

								seq 10 | sed -n 0~2p # even
								seq 10 | sed -n 1~2p # odd
							
0,/RE/
Porovnává s RE také první řádek
ADDR1,+N
Odpovídá řádek podle ADDR1 a následujících N řádků
ADDR1,~N
Odpovídá řádek podle ADDR1 a další řádky až do násedujícího řádku modulo N

Formating sequencesFormátovací řetězce

\n, \r, \t
Newline, carriage return, horizontal tab
\cX
CONTROL-X
\dXXX, \oXXX, \xXX
decimal / octal / hex ASCII value
\n, \r, \t
LF (NL), CR, TAB
\cX
CONTROL-X
\dXXX, \oXXX, \xXX
ASCII dekadicky / oktalově / hexa

							echo 𑁍 | sed s/./X/g    # Brahmi Punctuation Lotus (U+1104D)
							X
							echo 𑁍 | LC_ALL=C sed s/./X/g
							XXXX
						

Execute commands in shellSpouštění příkazů v shellu

e
Execute command in P.B. and replace with output
e command
Execute command and send output to output stream
e
Spustí příkaz v P.B. a nahradí jej za jeho výstup
e command
Spustí command a jeho výstup pošle do výstupního streamu

							sed -e 's/^/pwd/;e' -e 's,/,_,g' <<<''
							sed -n 'e date' <<<''
						

References and documentationOdkazy a literatura