4

Using sed how can I replace the lines that start with a star and replace it with numbers starting from 1?

I need to replace the (*) in the fist of a list with numbers using sed for example >

this file contain a list

*linux

*computers

*labs

*questions

to >>>>

this file contain a list

1 linux
2 computers
3 labs
4 questions

I tried using

sed -e 's/*//' file.in > file.out | sed -i = file.out
4
  • "with numbers starting from 1", what do you mean by this? That each replaced line should contain a number incremented by one from the last replaced line? If so, you may want to consider awk rather than sed. Additionally, is this a homework question? What have you tried?
    – HalosGhost
    Nov 7, 2014 at 2:36
  • 1) @Hauke Laging is right. 2) what have you tried so far?
    – HalosGhost
    Nov 7, 2014 at 2:48
  • I tried to print the star first but i couldn't Nov 7, 2014 at 2:50
  • I added numbers to your example output since you mention them but did not show them. Please make sure the output is what you want.
    – terdon
    Nov 7, 2014 at 18:56

6 Answers 6

8

You can use awk:

awk '/^\*/ {sub(/\*/, ++i)} 1' <<END
A list
* one
* two
Blah
* three
END
A list
1 one
2 two
Blah
3 three
1
  • I might be misunderstanding the OP, but I think he meant to replace the whole line, not just the star. Still though, +1 for awk.
    – HalosGhost
    Nov 7, 2014 at 15:02
7

You can play some trick - first number lines with * only then strip * and spaces if you want

nl -bp^[*] file | sed 's/^\s*\|\s*\*//g'
3
{   tr -s \\n |
    sed =|
    sed '$!N;s/\n./ /'
} <<\INPUT
*linux

*computers

*labs

*questions
INPUT

OUTPUT

1 linux
2 computers
3 labs
4 questions

nl is the most obvious, but sed can count lines. sed is not alone in that respect:

sh <<HD
$(sed -n 's/^\*\(.*\)/echo "$LINENO \1"/p' <infile)
HD

...or...

sed -n "s/..*/OUT='&'/p" <infile | 
PS1='${LINENO#0} ${OUT#?}${IFS#??}' dash -i

...both of which print the same as before (even if it is a little silly). I use dash here explicitly because, by default, it does not enable any readline like terminal reader. If dash is your sh you can just use sh, but if bash is linked in to sh you'll need to use the --noediting for the second example to avoid it printing the OUT=... stuff to the terminal as well.

And really, for your simple example case, the entire thing can be done with nl and tr:

tr -d \* <<\INPUT| nl -s ' ' -w1 -nln
*linux

*computers

*labs

*questions
INPUT

OUTPUT

1 linux

2 computers

3 labs

4 questions
3

I would use perl instead. The syntax for this is very simlar to sed's:

perl -pe 's/^\*/$c++/e' file

Or, to start from 1:

perl -pe 's/^\*/++$c/e' file

And to edit the original file in place:

perl -i -pe 's/^\*/++$c/e' file
1
  • "Or, to start from 1:...", why not just s/^\*/++$c/?
    – Joseph R.
    Nov 8, 2014 at 11:33
1

I can't come up with a solution that uses only sed, but this comes close. It uses only sed, shell builtins, and cmp and mv. With some effort and a modern shell, you could rewrite this to hold the file contents in shell variables, and not have to use cmp or mv.

#!/bin/sh
if test $# -ne 1
then
    echo usage: $0 file
    exit 1
fi
num=1    # start numbering at 1
infile="$1"
outfile="$1.out"
mv "$infile" "$outfile"    # set up so initial cmp always fails
while ! cmp -s "$infile" "$outfile" # repeat the sed until no more ^* can be found
do
    mv "$outfile" "$infile"
    # replace the first occurrence of ^* with a number and a space
    sed '0,/^\*/s//'$num' /' "$infile" > "$outfile" 
    num=$(expr $num + 1)
done
rm "$outfile"

test:

$ cat i
first line
*second
*third
fourth
*fifth
$ ./change i
$ cat i
first line
1 second
2 third
fourth
3 fifth
1
  • Maybe an extra newline at the end?
    – user44370
    Nov 8, 2014 at 0:49
-3

sed cannot do calculations thus this is not possible in a useful way.

4
  • 3
    This is really a comment, not an answer. And it can be done using sed, perhaps not pure sed, but still. Could you at least offer an alternative?
    – terdon
    Nov 7, 2014 at 18:34
  • @terdon Of course, "you can't" is an answer to "How can". And "not pure X" doesn't make much sense to me. That would apply to nearly every case. My answer was the first, and I expected the OP to react in a useful way i.e. "OK, an awk/perl/coreutils solution would do, too". Not my fault that he hasn't. Nov 7, 2014 at 21:57
  • Instead of waiting for him to react, offer him an alternative right away -_-. If he doesn't want an alternative, it would've helped someone else that stumbles upon this question.
    – Alaa Ali
    Nov 7, 2014 at 22:50
  • @HaukeLaging I know it's technically an answer which is why I haven't deleted it or converted it into a comment despite the two "Not an answer" flags that have been raised against it. It's just a particularly unhelpful answer. Next time, if you want the OP to react, post a comment, that's what they're for.
    – terdon
    Nov 8, 2014 at 16:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .