Search code examples
bashsedenvironment-variablesparameter-expansion

How to replace a variable's comma-separated string with whitespaces?


I have the following code at my docker-entrypoint script:

  if [[ -v SERVICE_NAMES ]]; then
    sudo sed -i -e "s#%SERVICE_NAMES%#$SERVICE_NAMES#g" /etc/someservice/someconfig.file
  else
    echo "SERVICE_NAMES variable not set, unable to write config without"
    exit 1
  fi

The content of the variable "SERVICE_NAMES" looks like this on container start:

hostname1,hostname2,hostname3

With my sed command I want to replace the SERVICE_NAMES variable with a placeholder within the someconfig.file, but separated using a whitespace not a comma, so that SERVICE_NAMES looks like this at my someconfig.file:

hostname1 hostname2 hostname3

Is it possible to replace the commas with whitespaces before I write to the file?


Solution

  • Using tr to transliterate commas to spaces

    The tr command can be used to transliterate a string (replace a character in a string with another character). The format is as follows:

    tr <character> <replacement-character>
    

    tr gets its input from stdin (file descriptor 0 or /dev/stdin) so we have to either create a Bash pipeline, use input redirection with process substitution, or use a here-string.

    # Pipeline
    echo "$SERVICE_NAMES" | tr ',' ' '
    # Input Redirection with Process Substitution
    tr ',' ' ' <<(echo "$SERVICE_NAMES")
    # Here-String
    tr ',' ' ' <<<"$SERVICE_NAMES"
    

    Using Bash's parameter expansion for expanding commas to spaces

    In Bash, parameter expansion can be used to replace all of the commas with spaces. The syntax is as follows: ${parameter/pattern/string}. However, you need to ensure that your pattern begins with another forward slash as per the man pages.

    If pattern begins with ‘/’, all matches of pattern are replaced with string. Normally only the first match is replaced.

    echo "${SERVICE_NAMES//,/ }"
    

    More sed commands

    The command sed can execute multiple commands in succession by adding more -e <command> arguments or by separating the commands with a ; (semicolon), however, any commands added will be applied to the whole file.

    To avoid affecting the whole file, we can make a separate call to sed with $SERVICE_NAMES as the data to operate on. We can use sed's y command to do transliteration on $SERVICE_NAMES.

    # Pipeline
    echo "$SERVICE_NAMES" | sed -e 'y/,/ /'
    # Input Redirection with Process Substitution
    sed -e 'y/,/ /' <<$(echo "$SERVICE_NAMES")
    # Here-String
    sed -e 'y/,/ /' <<<"$SERVICE_NAMES"
    

    Utilizing other scripting languages

    I won't provide examples for other scripting languages here since there are simply too many. In general, most scripting languages support string splitting, joining strings, regular expressions, string/character substitutions. Some examples of these languages are Python, JavaScript, AWK, and Perl.

    For solving issues like this with scripts, you can take your data and either place it directly into the script that will be executed, get the data to standard input (pipelines, input redirection, or here-strings), or utilize command-line arguments.