Skip to content

Instantly share code, notes, and snippets.

@emanuele6
Last active February 9, 2024 22:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emanuele6/d846879d025fbbac674b676df6682b70 to your computer and use it in GitHub Desktop.
Save emanuele6/d846879d025fbbac674b676df6682b70 to your computer and use it in GitHub Desktop.
POSIX ed script that adds line numbers in front of the lines of a file.
1s/^/1 /
2,$g/^/-t -\
s/ .*//\
s/^9*$/0&/\
t .\
s/^.*[^9]\(9*\)$/\1 /\
s/9/0/g\
-s/9*$//\
s/8$/9/\
s/7$/8/\
s/6$/7/\
s/5$/6/\
s/4$/5/\
s/3$/4/\
s/2$/3/\
s/1$/2/\
s/0$/1/\
.,+2j
w
q
@emanuele6
Copy link
Author

$ cat somefile.txt
this is a line
another line

hello
hi this is a line of text
$ ed -s somefile.txt < linenum.ed
$ cat somefile.txt
1 this is a line
2 another line
3 
4 hello
5 hi this is a line of text

@dmbarrad
Copy link

dmbarrad commented Feb 9, 2024

Hi
can you please explain how does it do what it does? I spent last hour trying, couldn't come up with something

@emanuele6
Copy link
Author

@dmbarrad Hello.

(example text file; > is the position of the cursor)

>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

The first command is 1s/^/1 / adds "1 " in front of the first line

>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

Then the second command is a 2,$g/^/... command that runs a sequence
of commands on all the other lines:

At the start of the first iteration, the cursor is at line 2:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
>eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

First, -t - copies the previous line, on the line before the current
line:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
>1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

Then s/ .*// removes everything after the first space on the current
line, leaving only the line number:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
>1
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

Then s/^9*$/0&/ prefixes a 0 to the number if it is all 9s, (e.g.
9 => 09, or 99 => 099); in this case it does nothing.

t . adds a copy of the current line after the current line (and moves
the cursor there)

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 1
>1
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

s/^.*[^9]\(9*\)$/\1 / (note that all lines can match this regexp
because a 0 is always prefixed to lines with only 9 earlier) replaces
the entire line with just the 9s at the end of the line followed by a
space (e.g. 129499 => 99 ); in this case it replaces 1 with
(n.b. the line is not empty, it contains a space):

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 1
> 
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

s/9/0/g replaces all those 9s with 0s, in this case it does
nothing.

-s/9*$// moves the cursor back to the previous line, and removes all
the 9s at the end of the line, if any (e.g. 1099 => 10); in this
case it just moves the cursor back:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
>1
  
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

s/8$/9/, s/7$/8/, s/6$/7/, s/5$/6/, s/4$/5/, s/3$/4/,
s/2$/3/, s/1$/2/, and s/0$/1/ in sequence basically increment the
last digit of the line by 1; that is how it gets 2 from the 1 of the
previous line:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
>2
  
 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

Finally .,+2j joins the current line with the following two lines
ending up with:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
>2 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 aliquip ex ea commodo consequat. Duis aute irure dolor in
 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
 culpa qui officia deserunt mollit anim id est laborum.

This sequence is then repeated for all lines in the file by the g
command:

 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
 2 eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
 3 ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
 4 aliquip ex ea commodo consequat. Duis aute irure dolor in
 5 reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
 6 pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
>7 culpa qui officia deserunt mollit anim id est laborum.

And in the end all the lines are prefixed with their line number.


To show a more interesting case:

 19299 For multiply, bring us grass fruit multiply from face two unto
>they're air were forth isn't itself.

-t -:

 19299 For multiply, bring us grass fruit multiply from face two unto
>19299 For multiply, bring us grass fruit multiply from face two unto
 they're air were forth isn't itself.

s/ .*//:

 19299 For multiply, bring us grass fruit multiply from face two unto
>19299
 they're air were forth isn't itself.

s/^9*$/0&/ (nothing)

t .

 19299 For multiply, bring us grass fruit multiply from face two unto
 19299
>19299
 they're air were forth isn't itself.

s/^.*[^9]\(9*\)$/\1 /: (n.b. there is a space at the end of the line)

 19299 For multiply, bring us grass fruit multiply from face two unto
 19299
>99 
 they're air were forth isn't itself.

s/9/0/g:

 19299 For multiply, bring us grass fruit multiply from face two unto
 19299
>00 
 they're air were forth isn't itself.

-s/9*$//:

 19299 For multiply, bring us grass fruit multiply from face two unto
>192
 00 
 they're air were forth isn't itself.

s/8$/9/ s/7$/8/ s/6$/7/ s/5$/6/ s/4$/5/ s/3$/4/ (nothing)

s/2$/3/:

 19299 For multiply, bring us grass fruit multiply from face two unto
>193
 00 
 they're air were forth isn't itself.

s/1$/2/ s/0$/1/ (nothing)

.,+2j:

 19299 For multiply, bring us grass fruit multiply from face two unto
>19300 they're air were forth isn't itself.

Another interesting case:

 9 foo
>bar

-t -:

 9 foo
>9 foo
 bar

s/ .*//:

 9 foo
>9
 bar

s/^9*$/0&/:

 9 foo
>09
 bar

t .:

 9 foo
 09
>09
 bar

s/^.*[^9]\(9*\)$/\1 /: (n.b. there is a space at the end of the line)

 9 foo
 09
>9 
 bar

s/9/0/g:

 9 foo
 09
>0 
 bar

-s/9*$//:

 9 foo
>0
 0 
 bar

s/8$/9/ s/7$/8/ s/6$/7/ s/5$/6/ s/4$/5/ s/3$/4/ s/2$/3/
s/1$/2/ (nothing)

s/0$/1/:

 9 foo
>1
 0 
 bar

.,+2j:

 9 foo
>10 bar

@dmbarrad
Copy link

dmbarrad commented Feb 9, 2024

Thanks a lot, this is genius. I love it.
Thank you for the script and for the explanation.
i couldn't understand it specifically because of the 9 replaced by 0 part and copying another line and the effect it had in the incrementation process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment