I have an variable in my script which I want to change:

read -p "Enter the name of city: " city
if [[ $city =~ Liverpool ]]; then
    sed -i -e "/\$type\_of\_city =/ s/= .*/= ${city}/" /cities  
    echo -e "Liverpool: `grep '$name_of_city' cities"

And in the city file there is a variable with # which I want to remove:

#$type_of_city = something

So I would like the same time changed something to Liverpool which in fact works with above code, but I do not know how to remove the # sign.

Now I get #$type_of_city = Liverpool but I want to see $type_of_city = Liverpool.

2 Answers 2


Correcting the code block somewhat,

read -p "Enter the name of city: " city
if [ "$city" = 'Liverpool' ]
    sed -Ei 's/^#* *(\$type_of_city) *= *.*/\1 = '"$city"'/' cities  
    printf "%s: %s\n" "$city" "$(grep -F "$city" cities)"

Here we match the line with the Extended RE ^#* *(\$type_of_city) *= *.*. Broken down it represents:

  • ^ - start of line
  • #* - zero or more # characters
  • * - zero or more spaces
  • () - a match on the enclosed block used later as \1
  • \$type_of_city - a literal string $type_of_city (\$ is escaped to prevent a false match to end-of-line)
  • * - zero or more spaces
  • = - literal character
  • * - zero or more spaces
  • .* - zero or more of any character

If the match succeeds we rewrite the line as \1 = $city, where \1 is the value of the bracketed () ERE match and $city is the variable's value.

Notice that we are dropping the value of the variable $city directly into the sed replacement string, so if it were to contain a character such as / or a sequence such as \1 it would produce (at best) unexpected results or even cause the sed to fail. In the current code this is protected with the if clause that requires the entered value to be Liverpool, but if you were to remove that or relax it too much you might hit this issue.


In your case, I would replace the entire line with sed, where the # is anchored as optional character right after start-of-line:

sed "s/^#\{0,1\}\$type_of_city =.*/type_of_city = $city/" /cities

This will replace

  • 0 or 1 occurences of # immediately after the start of the line (^), followed by
  • the literal string $type_of_city =, followed by
  • arbitrary text up to the end of line

with $type_of_city = , followed by the content of the shell variable $city.

The address specifier you used is not necessary, as replacements will only be performed if the search pattern matches.

Note that since you take $city from user input, you should be sure to validate/sanitize the input before use; otherwise you are opening your script to a code injection vulnerability if the user includes sed command syntax in the input.

As noted by Stéphane Chazelas in a comment, you can avoid this by using perl instead of sed where you can pass the value of $city via the environment or as argument instead of embedding it in the sed code.


You must log in to answer this question.

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