Gnu sed

From wikinotes
Revision as of 01:55, 30 April 2022 by Will (talk | contribs) (→‎Addresses)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Gnu sed performs search/replace within stdin or files.
See also bsd sed.

Documentation

man sed https://man.archlinux.org/man/core/sed/sed.1.en

Overview

sed lets you manipulate text streams using commands

example commands:

# 's' command search/replaces text
echo 'foo_bar_baz' | sed 's/bar/BAR/g'
> foo_BAR_gaz

# 'i'/'a' commands prepend/append newlines to each line
echo 'foo\nbar\nbaz' | sed 'i \my newline'
> my newline
> foo
> my newline
> bar
> my newline
> baz

# multiple commands can be separated by a ';'
# (lines not matching /bar/ will be deleted. AND lines matching bar will print their line number)
echo 'foo\nbar\nbaz' | sed '/bar/!d;='

By default, all commands operate on every line.
You can use addresses to limit the scope of a command.

# Limit scope of 'i' command to lines matching /bar/
echo 'foo\nbar\nbaz\bat' | sed '/bar/i \newline'
> foo
> newline
> bar
> baz
> bat

# Limit scope of 'i' to an address-range
# ',' between two addresses selects all lines in between the matches (inclusively)
# ( for range between /3/ and /5/, insert newline )
echo '1\n2\n3\n4\n5\n6' | sed '/3/,/5/i \newline'
> 1
> 2
> newline
> 3
> newline
> 4
> newline
> 5
> 6

Usage

Cookbook

Replace 'aaa' with 'bbb'

cat echo "aaa_stuff_aaa" \
    | sed 's_aaa_bbb_g'

regex search/replace

# replace one-or-more 'a's with a single 'b'
cat echo "aaa_stuff_aaa" \
    | sed -E 's_[a]*_b_g'

# Group matching (\2 is a variable that refers to the
# second match group. In this case, 'stuff'
cat echo "aaa_stuff_aaa" \
    | sed -E 's_\([a]*\)\(stuff\)_\2\n'

search/replace and write file

# Replace file contents
sed -i"bak"  "s_aaa_bbb_g" /path/to/file

print range between two-matches, and prepend line-number

# Print lines from address-range, prepending line-number
echo '1\n2\n3\n4\n5\n6' \
    | sed '/3/,/5/!d;='  `# delete non-matching lines, prepend line-no above each matching line` \
    | sed 'N;s/\n/:\t/'  `# include next-line in match, replace '\n' with ':\t'
> 3:    3
> 4:    4
> 5:    5

Extract key-value from INI section

delete_non_section_lines='/^\[MY_SECTION\]/,/^\[/!d'
delete_non_matching_keys='/^[ ]*MY_KEY[ ]*=/!d;'
get_value='s/.*=[ ]*//'

value=$(cat ~/some-config.ini \
    | sed -E "${delete_non_section_lines};${delete_non_matching_keys};${get_value}")

Addresses

/foo/        # select lines matching regex
/foo/,/bar/  # select lines matching regex(foo), regex(bar), and all lines in between
/foo/!       # select lines NOT matching /foo/ (requires command after '!')
5,10         # lines 5-10 inclusively