I looked at other similar questions but the answers did not help me. I am new to bash and probably have a syntax error in my script but I can't figure out where. I was trying to update users in the example.conf file every time this script is run. Each user has a name.pub file.

VAR1=$( ls  | grep ".pub" |sed "s/.pub//g")
VAR2="@demo_project_users = "
sed  "s/@demo_project_users = .*/$res/g" example.conf

This is producing the Unterminated 's' command error.

Edit: I have these files in a folder

aaaaaaaaaa.pub  eboh.pub      get_usernames.sh  mmusterfrau.pub  plom.pub   rrein.pub  update_users.sh
dboh.pub        example.conf  leni.pub          mmustermann.pub  rcall.pub  tani.pub

and I want to get all user names (without .pub) in one row with a space inbetween, like this

@demo_project_users = (... all  names here)
  • Please try to add \ before spaces like s/@demo_project_users\ =\ .*/$res/g
    – binarysta
    Commented Apr 26, 2020 at 19:37
  • 1
    "Each user has a name.pub file" so likely VAR1 is a multi-line string? Commented Apr 26, 2020 at 19:40
  • 1
    @binarysta The spaces in the pattern is not an issue.
    – Kusalananda
    Commented Apr 26, 2020 at 19:49
  • @steeldriver if I echo VAR1, the output is in one line Commented Apr 26, 2020 at 19:52
  • 2
    @FiloménaPetržlénová Yes, but try echo "$VAR1". Remember to always quote variable expansions.
    – Kusalananda
    Commented Apr 26, 2020 at 19:59

2 Answers 2


Your grep is likely matching more than one filename, which gives a value in $res that contains newlines. GNU sed would complain exactly the way that you describe when using a replacement string that contains literal newlines.

Don't use grep to filter the output of ls. If you want to get all names in he current directory matching the pattern *.pub, use

filenames=( *.pub )

This would create an array containing all names that matches the given pattern.


sed 's/\(@demo_project_users = \).*/\1'"${filenames[*]%.pub}"'/g' example.conf

The "${filenames[*]%.pub}" expansion will expand to a single string consisting of each of the filenames in the filenames array, delimited by spaces (or whatever the first character of $IFS happens to be; a space by default), and with the suffix string .pub removed from each one.

It's the "${filenames[*]}" bit that expands to the space-delimited string, and its the %.pub bit that removes the .pub suffix from each filename.

  • I made an edit, I need to process multiple filenames, not just one Commented Apr 26, 2020 at 19:50
  • @FiloménaPetržlénová I made an update.
    – Kusalananda
    Commented Apr 26, 2020 at 19:58
  • thank you, your answer helped a lot Commented Apr 26, 2020 at 20:10

The substitution of $res into the command is done by the shell. If there's a slash in the value, sed has no way to know that it isn't the end marker for the s command. Likewise sed will interpret any backslash or ampersand in $res as a special character.

If backslashes and ampersands cannot possibly appear in $res and there's another character that you know cannot possibly appear as well, use that character as a separator. For example:

sed  "s~@demo_project_users = .*~$res~g" example.conf

Alternatively, quote special characters by adding a backslash before them.

quoted_res=$(printf %s "$res" | sed 's/[\\\/&]/\\&/g')
sed  "s/@demo_project_users = .*/$quoted_res/g" example.conf

You must log in to answer this question.

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