bash - Shell: Find and replace word

06
2013-08
  • smokinguns

    I have a string in my shell script which is in a fixed format : '[STATUS REPORT] PROJECT'. When user executes my shell script he will be asked to provide a value for 'PROJECT'.

    I would like to replace the word 'PROJECT' with the user provide value. For Eg if 'ABCD' was user input:

    '[STATUS REPORT] ABCD'

    I have two issues: 1: How to tackle special characters like '&' in a project name? For eg:

    echo "[STATUS REPORT] PROJECT" |  awk '{ gsub(/PROJECT/, "A&A"); print }' 
    

    and I get the following output:

    [STATUS REPORT] APROJECTA

    2: My actual shell statement looks like this:

    echo "[STATUS REPORT] PROJECT" |  awk '{ gsub(/PROJECT/, $ProjectName); print }'
    

    where $ProjectName stores the project name provided by user. But this doesn't seem to work

    How can I get this working properly?

  • Answers
  • jfgagne

    This will solve your 1st issue:

    echo "[STATUS REPORT] PROJECT" |  awk '{ gsub(/PROJECT/, "A\\&A"); print }'
    

    (& is a special char in awk substitution: it means "what has been matched". You need to escape if with a \. And as you are in a awk string, your need to put 2 \ to produce one as \ escape the next char as in \n.)

    This will solve your 2nd issue:

    ProjectName=toto
    echo "[STATUS REPORT] PROJECT" |  awk -v "ProjectName=$ProjectName" '{ gsub(/PROJECT/, ProjectName); print }'
    

    (Edit: notice the newly added " around ProjectName=$ProjectName so a space in ProjectName does not break the script.)

    But awk is a big tool to perform string substitution, you might want to use sed:

    echo "[STATUS REPORT] PROJECT" |  sed -e 's/PROJECT/A\&A/'
    ProjectName=toto;
    echo "[STATUS REPORT] PROJECT" |  sed -e "s/PROJECT/${ProjectName//\//\\/}/"
    

    (Edit: a / in ProjectName will was breaking the initial solution. I added the escaping of slashes, but some other char(s) still breaks it: &, \1, ... I think plain bash shell bellow is safer.)

    or in plain bash shell:

    msg="[STATUS REPORT] PROJECT"
    echo ${msg//PROJECT/A&A}
    ProjectName=toto
    echo ${msg//PROJECT/$ProjectName}
    
  • Nithin Philips

    (Sorry, I don't have commenting privileges here)

    From the snippet you've posted it's not very clear why you need to pipe the string to awk.

    You can simply use the variable within the echo statement and bash will replace the variable:

    echo "[STATUS REPORT] $ProjectName"
    

  • Related Question

    bash - Shell Script if else
  • user34104
    #!/bin/bash
    echo "Int. a number"
    read num1
    echo "Int. another numer"
    read num2
    if ["$num1"="$num2"]; then
    echo "Equals"
    else
    echo "Dif"
    fi
    if["$num1"<0]; then
    echo "The number $num1 is negative"
    else if ["$num2"<0]; then
    echo "The number $num2 is negative"
    fi
    #
    

    this code is not working, i've something wrong when i see if the number is < 0.

    thanks


  • Related Answers
  • Marian

    Wrong syntax. Please read the documentation about the [ command (help [ / help test)

    Each argument must be an argument of its own, ie you must use spaces inbetween: [ "$num1" == "$num2" ]. The reason why you don't see an error with the first check is that it tries to find a command named (with num1=3 and num2=4) [3==4], which does not exist, so the expression evaluates to false. At the first check, you wrote a <, which is a shell operator for input redirection. It tries to open the file 4], which in most cases does not exist.

    However when comparing numbers, you should use -eq and similar, == is for string comparison: [ 3 == 3.0 ] is false, [ 3 -eq 3.0 ] is true.

  • Dennis Williamson

    In Bash, you can do numeric comparisons with the familiar operators if you use arithmetic evaluation:

    if ((num1 ==num2 ))
    
    if ((num1<0))    # in this context, < is not evaluated as a redirection operator
    
    else if (( $num2 < 0 ))
    

    As you can see, I've been fairly free with my use of spaces and can omit the dollar sign if I want. You should be aware of this, however:

    a=    # set to nothing, thus null
    if (( a == 0 )); then echo "ok"; fi    # echoes "ok" since a evaluates to 0
    if (( $a == 0 )); then echo "ok"; fi    # produces an error even if $a is quoted
    

    String comparisons can be performed with "<" and ">" instead of "-lt" and "-gt" if you use double square brackets. The requirement for spaces is the same with them as it is for single square brackets.

    s="b"
    if [[ "$s" > "a" ]]
    t=    # null
    if [[ $t < "a" ]]    # evaluates to true
    

    As you can see in the last example, when using double square brackets, it's not necessary to quote variables to protect against the possibility of them being null or unset, unlike when using single square brackets.

  • Brian

    The operators you are using do string comparison. You should use -eq for integer equality, -lt for less than, etc (they should also be surrounded by spaces).