1

I thought my bash-fu was strong enough but apparently it isn't. I can't seem to figure this out. I would like to do something like this:

  var="XXXX This is a line"
  word_to_replace="XXXX"
  # ...do something
  echo "Done:${var}"
  Done:     This is a line

Basically I want to quickly replace all characters in a word with spaces, preferably in one step. Note, if it makes things easier var currently will be at the start of the string although it may have leading spaces (which would need to be retained).

In python I would possibly do this:

>>> var="XXXX This is a line"
>>> word_to_replace="XXXX"
>>> var=var.replace(word_to_replace, ' '*len(word_to_replace))
>>> print("Done:%s" % var)
Done:     This is a line
lonetwin
  • 971
  • 10
  • 17

4 Answers4

3

Here's one way you could do it, using a combination of shell parameter expansion and the sed command.

$ var="XXXX This is a line"
$ word_to_replace="XXXX"
$ replacement=${word_to_replace//?/ }
$ sed "s/$word_to_replace/$replacement/" <<<"$var"
     This is a line

? matches any character and ${var//find/replace} does a global substitution, so the variable $replacement has the same length as $word_to_replace, but is composed solely of spaces.

You can save the result to a variable in the usual way:

new_var=$(sed "s/$word_to_replace/$replacement/" <<<"$var")
Tom Fenech
  • 72,334
  • 12
  • 107
  • 141
  • 2
    You don't need `sed`, and it can be surprising if `$word_to_replace` includes slashes or some special characters like, dots, asterisks, etc. –  May 04 '17 at 12:04
1

In plain Bash:

If we know the word to be replaced:

$ line=" foo and some"
$ word=foo
$ spaces=$(printf "%*s" ${#word} "")
$ echo "${line/$word/$spaces}"
     and some

If we don't, we could pick the string apart to find the leading word, but this gets a bit ugly:

xxx() {
   shopt -s extglob              # for *( )
   local line=$1
   local indent=${line%%[^ ]*}   # the leading spaces
   line=${line##*( )}            # remove the leading spaces
   local tail=${line#* }         # part after first space 
   local head=${line%% *}        # part before first space...
   echo "$indent${head//?/ } $tail"  # replace and put back together
}
$ xxx "  word on a line"
        on a line

That also fails if there is only one word on the line, head and tail both get set to that word, we'd need to check for if there is a space and handle the two cases separately.

ilkkachu
  • 6,221
  • 16
  • 30
0

I use GNU Awk:

echo "$title" | gawk '{gsub(/./, "*"); print}'

This replaces each character with an asterisk.

EDIT. Consolidated answer:

$ export text="FOO hello"
$ export sub="FOO"
$ export space=${sub//?/ }
$ echo "${text//$sub/$space}"
    hello
  • 2
    This replaces every character with an asterisk, which is not what has been asked and which can be implemented much easier with `tr -c '' '*'` – ceving May 04 '17 at 09:33
  • Then apply `tr` or whatever to `$word_to_replace` and use bash string substitution. –  May 04 '17 at 10:18
  • BTW, `tr -c '' '*'` will replace new line as well if any. –  May 04 '17 at 10:19
  • If you removed the awk option and all the `export`s from the bash option, possibly adding some explanation, then this would be the best option in my opinion. – Tom Fenech May 04 '17 at 12:32
0

Using sed:

#!/usr/bin/env sh

word_to_replace="XXXX"
var="$word_to_replace This is a line"

echo "Done: $var"

word_to_replace=$(echo "$word_to_replace" | sed 's,., ,g')
var="$word_to_replace This is a line"
echo "Done: $var"
Arkadiusz Drabczyk
  • 11,227
  • 2
  • 25
  • 38
  • This appears like an answer but isn't exactly what I was looking for because it recreates the line rather than replace the word. For instance if the line had leading spaces before the word to replace, like I mentioned in the question, how would this solution be adapted ? Good approach tho', I might have to do it this way -- split the line, replace all characters in the word with space and recreate the line. – lonetwin May 04 '17 at 09:45
  • `newline=${oldline//$word_to_replace/$replacement}` –  May 04 '17 at 10:21
  • @Igor ehe ...what would `$replacement` be ? – lonetwin May 04 '17 at 10:29
  • `replacement=${word_to_replace//?/ }` from below. –  May 04 '17 at 10:30
  • 1
    @Igor you misunderstood the question. With what you suggest `${word_to_replace}` will be replaced with a *single* space. The question was about replacing all characters with as many spaces as the length of `${word_to_replace}` – lonetwin May 04 '17 at 10:40
  • 1
    No. Did you actually try the thing: `${foo//?/*}`. –  May 04 '17 at 12:00