3

So I have a list of random websites of the following kind:

   rapido21655bonk.a.sweetpotato.net
   rapido26230bonk.a.sourpotato.net
   rapido29926bonk.b.sourpotato.net
   rapido29926bonk.b.sweetpotato.net
   rapido30179bonk.a.sweetpotato.net
   rapido30648bonk.b.sourpotato.net
   rapido30761bonk.c.sweetpotato.net

Now I need a sed string to only leave the number, and take everything else out. What I did was: sed s/rapido// to get rid of the first part of it, but for the second part, I could use sed twice to get rid of them both, but I want to know if I can use some kind of or logic to remove both in one sed. I know I can use sed to match a or b or c using [abc] but I want something like that for whole words. So what I did after this was:

sed s/rapido//|sed s/bonk.[abc].sweetpotato.net// and then I would put another one with just sourpotato.net, but I can't seem to do the following:

sed s/rapido//|sed s/bonk.[abc].(sweet|sour)potato.net// This doesn't work. It gives me this: -bash: syntax error near unexpected token('`

Only replacing the number doesn't not work, because sometimes I might get stuff like rapido22452boonkers.red which I would want to still have there. I would want to ONLY remove the 2 alternatives sweetpotato.net OR sourpotato.net.

[111@111 ~]$ sed s/rapido// sedster|sed 's/bonk.[abc].(sweetpotato|sourpotato).net//'
   21655bonk.a.sweetpotato.net
   26230bonk.a.sourpotato.net
   29926bonk.b.sourpotato.net
   29926bonk.b.sweetpotato.net
   30179bonk.a.sweetpotato.net
   30648bonk.b.sourpotato.net
   30761bonk.c.sweetpotato.net
0

5 Answers 5

2

If you just want to extract the numbers, you can do this with GNU grep:

$ grep -oP '\d+' file
21655
26230
29926
29926
30179
30648
30761

Or, portably with perl:

$ perl -pe 's/[^\d\n]+//g' file
21655
26230
29926
29926
30179
30648
30761

Or sed:

$ sed -nE 's/[^0-9]+//gp' file
21655
26230
29926
29926
30179
30648
30761

If you need something more specific to your input data, you can try:

$ sed -nE 's/.*rapido([0-9]+)bonk\..\.(sweet|sour)potato.net.*/\1/p' file
21655
26230
29926
29926
30179
30648
30761
4
  • Thanks for the help, but only replacing the number doesn't help me, because sometimes I might get stuff like rapido22452boonkers.red which I would want to still have there. I would want to ONLY remove the 2 alternatives sweetpotato.net OR sourpotato.net. Commented Dec 30, 2018 at 16:49
  • 3
    @sweetsourpotato see update. But please remember to make that sort of thing clear when asking a question. Ideally, you need to ask showing an example of your input data that covers all possible cases and the output you want from it.
    – terdon
    Commented Dec 30, 2018 at 16:50
  • Thank you, but what does this do? /\1/p I mean, using (word1|word2) gave me a bash error, so will that help? Commented Dec 30, 2018 at 16:54
  • @sweetsourpotato what error? Did you use the exact command? The \1 refers to the 1st captured group, the ([0-9]+), so it will replace the entire match with what was captured. The p means "only print if the substitution was successful" so any lines not matching the pattern will be skipped (the -n means "don't print unless I tell you to"). Your question suggested you only want the numbers, so I wanted to skip any lines that didn't match. If that's not what you want, remove the -n and -p and edit your question to clarify.
    – terdon
    Commented Dec 30, 2018 at 17:00
1

With

sed -r 's/([^0-9]*)([0-9]*)([^0-9]*)/\2/g'

you can keep only the number in the middle. This only works with extended regular expressions, so you need the -r option to sed.

Actually, it suffices to use

sed -r 's/([^0-9]*)([0-9]*)(.*)/\2/g'

This uses the function of referencing parts of the expression with \1, \2, ... You then have to use parentheses (...) around the part of your expression you want to reference. In the above code, the second part ([0-9]*) will match the number in the middle, and you can refer to this by \2.

Edit: As terdon pointed out, we don't need to capture the initial part since we don't use it again. So

sed -n -r 's/[^0-9]*([0-9]+).*/\1/p'

is enough.

To summarize, the command above keeps only the first number in your input line.

8
  • I don't understand this part of it though /\2/, I want it replaced with nothing, like // Commented Dec 30, 2018 at 16:45
  • @sweetsourpotato It works, just try it, for example echo ab234bc | sed -r 's/([^0-9]*)([0-9]*)(.*)/\2/g' Commented Dec 30, 2018 at 16:50
  • 1
    There's no reason to capture the groups you won't be using, but you do need + or [0-9][0-9]* so it won't match when there are no numbers. You also don't want the g there as far as I can tell. This should be enough: sed -r 's/[^0-9]*([0-9]+)(.*)/\1/'.
    – terdon
    Commented Dec 30, 2018 at 16:52
  • What I don't understand is why I get a syntax error if I use (word1|word2) Commented Dec 30, 2018 at 16:58
  • @sweetsourpotato we can't help you if you don't show your syntax error. If you used the command from your updated question, the error is because you're not quoting the sed pattern. Note how both this answer and my own have sed 'blah blah' and not just sed blah blah.
    – terdon
    Commented Dec 30, 2018 at 17:01
0

Your attempt

sed s/rapido// | sed s/bonk.[abc](sweet|sour)potato.net//

was actually pretty close, but you made two mistakes. The first is that you didn't put the command inside quotes, so bash interpreted the special characters "(" and "|". (The fact that you got a bash error message should have tipped you off to this).

The second mistake is more subtle. Sed and grep use basic regular expressions, in which only a few characters ( . * ^ $ [ ] ) have special meaning. If you want to use extended regex operators ( | () {} ), you need to precede them with a backslash. So here's what your command should have looked like:

sed < t 's/rapido//' | sed 's/bonk.[abc].\(sweet\|sour\)potato.net//'

and since sed can handle multiple commands in one run, you can simplify this to

sed < t 's/rapido//; s/bonk.[abc].\(sweet\|sour\)potato.net//'
0
sed -e '/\.\([abc]\.\)\{0,1\}\(sweet\|sour\)potato\.net$/s/[^0-9]//g'

Select the lines to be edited and then remove the nondigits from those.

To make it llook less cluttered, use the -r option of sed:

 sed -re '/[.]([abc][.])?(sweet|sour)potato\.net$/ s/[^0-9]//g' 
1
  • Beware \| and -r are GNUisms and what [0-9] matches is unspecified outside the POSIX/C locale (and sometimes random in practice depending on the sed/libc/gnulib implementation/version and locale) Commented Mar 15, 2023 at 19:58
0

To remove everything but the numbers, tr is a solution:

x='21655bonk.a.sweetpotato.net
   26230bonk.a.sourpotato.net
   29926bonk.b.sourpotato.net
   29926bonk.b.sweetpotato.net
   30179bonk.a.sweetpotato.net
   30648bonk.b.sourpotato.net
   30761bonk.c.sweetpotato.net'
printf '%s\n' "$x" | tr -d '[:alpha:].' 
21655 26230 29926 29926 30179 30648 30761

or

printf '%s\n' "$x" | tr -cd '0-9 ' 
2
  • The first one preserves the newline characters, so you shouldn't be getting that output. Commented Mar 15, 2023 at 19:55
  • Beware what 0-9 matches is unspecified outside the POSIX/C locale. You may prefer tr -cd '0123456789 ' or tr -cd '[:digit:] ' Commented Mar 15, 2023 at 19:56

You must log in to answer this question.

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