2

I am trying to write a script that takes two files as arguments and changes an .svg file with values from a .csv file. Csv file consists of lines with two values; id,colour. I need to find the id in the svg file and add the colour to the line where id matches I don't know if my problem is the sed part, since it gets complicated when variables are introduced within the change, or the script is fundamentally flawed.

id=($(cut -f1 -d, $2))
colour=($(cut -f2 -d, $2))
file=$1
name=$(basename -s .svg $1)
name1=$(echo "$name""1")
cat $2 | while IFS=, read id colour; do 
sed -i "s/id=\"'"$id"'\"/id=\"'"$id"'\" style=\"fill:\"'"$colour"'\";\"/" "$1"
done

When I use this sed -i 's/id="ca"/id="ca" style="fill:red;"/' data.svg this changes the file, but when I change the "ca" with "$id" or '"$id"', it doesn't work.

I've also tried this :

cat $2 | while IFS=, read id colour; do 
sed -i 's/id='"$id"'/id='"$id"' style="fill:red;"/' "$1"
done

the result I am getting is this: <g id= style="fill:red;""hi"> the expected result was this :
<g id="hi" style="fill:red;">

And when I put $colour to sed, sed -i 's/id='"$id"'/id='"$id"' style="fill:'"$colour"';"/' "$1" like this, I get this: <g id= style="fill:;""hi">

1
  • If I were at you, I would use while loop instead and use break statement where it is not matching. Could you explain this question a little bit more with some more example?
    – Rakib Fiha
    Dec 10, 2019 at 17:05

1 Answer 1

2
  1. You shouldn't need to read the CSV into variables, you can just loop on the CSV directly:
cat data.csv | while IFS=, read id colour; do # something with $id and $colour
  1. Doing var=$(echo text) is kind of redundant - you should just use var="text" directly.

  2. I'm not sure what you mean by the construct [ "grep -E..." ], but that is basically testing if the string in the test is not empty, which it isn't because you just put some text in it.

When writing bash scripts it is a good idea to test each expression in turn and see that it behaves as you expect, from the command line (*) - this way a lot of surprises will be eliminated. Writing a complete script and then running it, without a lot of experience on how to write scripts well, is probably a good way to shoot yourself in the foot. I have many years of experience writing bash scripts, and I still try and fail a lot on the command line before putting things down to script. When you do run your script, running it with -x to enable tracing of the commands will prove very helpful.

I would guess that the main reason you can't get the replacement to work is that the SVG file uses double quotes (") for the ID attribute and not single quotes as in your sed expression.

When constructing sed expressions in a shell script, its often annoying to deal with all the escaping. If possible I usually like to have the sed expression not quoted at all, which is one of the reasons why I often use regexp delimiters that aren't slashes (as we will next see). You need to put in the values of the id and colour into the sed expression while also correctly identifying the quoting of the SVG attributes. One thing that might work would be this:

sed -i "s,id=\"$id\",id=\"$id\" style=\"fill:$colour;\"," "$1"

Here we just used double quotes around the expression - which allows us to embed the variables - and just escape the double quotes to match to prevent them from terminating the shell string.

Another option would be to composed the sed expression from multiple strings that have different quoting rules:

sed -i 's,id="'"$id"'",id="'"$id"'" style="fill:'"$colour"';",' "$1"

Here we put all the static text in single quotes, and then just terminate the single quotes and open a double quoted string to have the variables parsed. This works because there are no spaces between the single quoted strings and the double quoted strings, and as long as there are no spaces, Bash passes all that as a single argument to sed. But Obviously that's a bit confusing, so I prefer the first style.

Another thing that we can do, is to use sed capture groups to not type id="$id" more than once:

sed -i "s,\(id=\"$id\"\),\1 style=\"fill:$colour;\"," "$1"

The \( and \) capture the thing that was matched, and \1 drops it back into the substituted string. *) If you have done scripting in MS-Windows you are probably aware of the sad sad situation there where the command line (whether CMD or powershell) behaves differently then running the same commands in scripts, in often non-obvious ways. This is not the situation in Unix scripting shells such as Bash.

10
  • Well what I tried to do with if was "if you match the id, then use this sed to change it." What can I do to correct my sed, I feel like I've tried every possible combination of quotes?
    – arty
    Dec 10, 2019 at 16:33
  • Did you try to just run the sed command, manually, with one id and color? did it output an error or just copied the file as is?
    – Guss
    Dec 10, 2019 at 16:34
  • It works manually with a specific id and colour. But when I put the variables in, it doesn't and I get this error message: Error reading SVG:Error domain 1 code 5 on line 53 column 1 of data: Extra content at the end of the document
    – arty
    Dec 10, 2019 at 16:50
  • Can you share the sed command that works?
    – Guss
    Dec 10, 2019 at 16:54
  • 1
    Well - it works when you use double quotes around the id - in your script you use single quotes , and that doesn't work. Use double quotes in your script. Also, you probably want to add this example to the question.
    – Guss
    Dec 10, 2019 at 17:03

You must log in to answer this question.

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