4

I want to replaced all number with '@' symbol. I am using the below sed command , but not getting the desired result.

command -

echo "abc 434 pankaj 444" | sed 's/[0-9]*/@/g'

Result -

@a@b@c@ @ @p@a@n@k@a@j@ @
1
  • 1
    echo "abc 434 pankaj 444" | sed 's/[0-9]/@/g' Dec 3, 2017 at 16:32

6 Answers 6

8

Well, quite simply, [0-9]* matches strings that consist entirely of zero or more digits, include empty strings. Anything that matches an empty string, matches between any two characters, so the replacement @ is added between all letters in the input. Strings of multiple digits are replaced with one @ since the expression matches all consecutive digits at once.

So in the input string ab43 the matches to [0-9]+ are (with some whitespace added for clarity):

    a   b   434
  ^   ^     ^^^- here, a string of some digits
  ^   ^- here, a zero-length string
  ^- here, a zero-length string

Use [0-9] to match exactly one digit, or [0-9][0-9]* to match one or more (or [0-9]+ in extended regular expressions).

10
  • then the regex pattern should replace all alphabets with '@' symbols, since alphabets has zero digits. Dec 3, 2017 at 17:20
  • @PankajPandey, err, right. I rephrased that a bit.
    – ilkkachu
    Dec 3, 2017 at 17:26
  • @PankajPandey, should they be? Neither [0-9]* nor [0-9] match any letters, and I thought you wanted to replace only numbers?
    – ilkkachu
    Dec 3, 2017 at 17:37
  • by that logic, alphabetic characters should also be replaced by '@' since they also do not match to any of the digits. Dec 3, 2017 at 17:38
  • i just want to understand the behaviour of sed command, as I feel it's behaviour is somewhat erratic. Dec 3, 2017 at 17:38
0

Replace each digit with @

echo "abc 434 pankaj 444" | sed 's/[0-9]/\@/g'
#Output: abc @@@ pankaj @@@

or replace each number with @

echo "abc 434 pankaj 444" | sed 's/[0-9]\+/\@/g'
#Output: abc @ pankaj @

depending on the desired output you need

2
  • Why escape the @ in the replacement, and why -E? Also, why not tr '0-9' '@'? However, this would replace all digits with @, not all numbers. One could potentially read the question in a way that means that the wanted output should be abc @ pankaj @.
    – Kusalananda
    Sep 9, 2020 at 12:39
  • Note that \+ is a GNU extension. The standard equivalent is \{1,\}. With -E (soon to be standard), you can use + or {1,}. Sep 9, 2020 at 13:01
0
echo "abc 434 pankaj 444"| tr "[0-9]" "@"

abc @@@ pankaj @@@
0

Replace * with any special character can be achieved by using tr command.

#!/bin/bash
mystring="This is my number: 12345"
echo $mystring | sed 's/[0-9]/*/g'
1
  • 2
    tr is certainly one tool that can be used. But your example doesn't explain how - you used sed, not tr. Also your answer suggests that what OP wants to do requires a script and a variable - surely this is not what you want to say? Sep 25, 2021 at 20:03
0

Depending on whether you want to replace digits or whole numbers (runs of consecutive digits) with @, you may use the tr command without or with its -s option:

$ echo "abc 434 pankaj 444" | tr '[:digit:]' '[@*]'
abc @@@ pankaj @@@
$ echo "abc 434 pankaj 444" | tr -s '[:digit:]' '[@*]'
abc @ pankaj @

The -s option of tr makes the utility "squeeze" any consecutively occurring character from the second argument found in the data. In this case, using -s makes tr combine runs of @ characters into single @ characters.

The two arguments [:digit:] and [@*] tell tr to replace digits with @ characters. Most (all?) implementations of tr allow you to write @ in place of [@*] as the second argument. The [@*] literally means "as many @ as there are characters in the set described by the first argument".

Note that tr will squeeze any pre-existing runs of consecutive @ characters in the input if -s is in effect.


Your approach with sed does not work as expected because you insert a @ character wherever there are zero or more matches of a digit. There are zero digits between each character in the input, so the expression matches between each character.

A modified substitution that would work correctly and replace runs of digits with a single @ would be

sed 's/[[:digit:]]\{1,\}/@/g'

By using \{1,\} in place of * (which in itself is the same as \{0,\}) we force at least one match of the preceding expression. You will see \{1,\} written as + in extended regular expressions.

By removing \{1,\} from the expression, leaving the substitution as s/[[:digit:]]/@/g, you replace each individual digit with a @.

2
  • 1
    Beware though that echo @@123@@ | tr -s '[:digit:]' '[@*]' outputs @ Sep 26, 2021 at 15:50
  • @StéphaneChazelas That's a big whoops. I will add the necessary notices to the text. Thanks!
    – Kusalananda
    Sep 26, 2021 at 16:12
-1

You can achieve this by awk command too


echo "abc 434 pankaj 444" |awk '{gsub("[0-9]","@",$0);print $0}'

1
  • 1
    While true, sed is the right tool for the job and will work given a small modification. Dec 3, 2017 at 18:24

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.