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
  • "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 '14 at 2:36
  • 1) @Hauke Laging is right. 2) what have you tried so far? – HalosGhost Nov 7 '14 at 2:48
  • I tried to print the star first but i couldn't – Abdulaziz Hamoud Nov 7 '14 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 '14 at 18:56
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
|improve this answer|||||
  • 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 '14 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'
|improve this answer|||||
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
|improve this answer|||||
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
|improve this answer|||||
  • "Or, to start from 1:...", why not just s/^\*/++$c/? – Joseph R. Nov 8 '14 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
|improve this answer|||||
  • Maybe an extra newline at the end? – user44370 Nov 8 '14 at 0:49
-3

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

|improve this answer|||||
  • 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 '14 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. – Hauke Laging Nov 7 '14 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 '14 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 '14 at 16:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.