1

I want to replace some strings with other strings in a folder containing .ly files (.ly files are files used to write music, which can then be converted to svg files). One problem is that the files contain backslashes (\).

Anyway, what I want to do is to replace the following strings:

\f  with \fffff 
\p  with \ppppp
mordent  with reverseturn 
r4  with \mordent 

Each string I want to replace (and each string it is replaced for) has a space in the end. This is because I don't want strings like

\pt to be replaced with \pppppt

Similarly, because backslashes matter, strings like

\ff should stay the same (only f with a slash before and a space after should be replaced).

The code that I am using to achieve this is:

for f in *.ly
do 
    filename="${f}"
    sed -i -- "s@\p @\ppppp @g; s@\f @\fffff @g; s@mordent @reverseturn @g; s@r4 @\maxima @g" $filename;

done

I am using delimited @ instead of backslash exactly to achieve this.

However, the program is giving some totally weird behavior. In particular:

\f  stays the same (wrong behavior, the right behavior is to get transformed to \fffff)
\p  is converted to \ppppp (correct behavior)
\stemUp  is converted to \stemUppppp (wrong behavior, the right behavior is to remain as it was)

This is perplexing me and giving me a headache. In particular, why it works correctly for \p but not for \f considering that it is the exact same code.

For reference, I attached a file before and after applying the sed commands.

Thanks in advance for any help!

NB: I am using Ubuntu 16.04 and sed (GNU 4.2.2).

TheRevanchist
  • 301
  • 1
  • 4
  • 11
  • You probably need to escape the \ inside the double quotes properly. I'd recommend to use single quotes for `sed` programs, i.e. `'s@\p @\ppppp@g;…'`, and than you need to escape the special meaning of \ inside sed, i.e. `'s@\\p @\\ppppp@g;…'`. – Robin479 May 09 '18 at 14:54
  • 1
    `\f` and `\p` behave differently because `\f` is interpreted as "formfeed", whereas `\p` simply becomes `p`. You have to escape the backslash to be interpreted literally (also within single quotes, as it is sed that interprets the string). Use a plain `p` in your input and you'll see that it is substituted as well when using just `\p` instead of `\\p`. – Benjamin W. May 09 '18 at 15:02
  • Thanks, everything is clear now. – TheRevanchist May 09 '18 at 15:05

1 Answers1

3
$ echo '12p3 p \p foo' | sed 's/\p /\ppppp /g'
12p3 ppppp \ppppp foo
$ echo '12p3 p \p foo' | sed 's/\\p /\\ppppp /g'
12p3 p \ppppp foo
Sundeep
  • 19,273
  • 2
  • 19
  • 42
  • 1
    Thanks! I understand that this work however I sill don't get why it was working before for \p but not for \f. Quantum mechanics, I guess. – TheRevanchist May 09 '18 at 15:02
  • I recreated your same problem and had the same result, double quotes work in finicky ways with sed and backslashes, avoid at all costs. – Reg Smith May 09 '18 at 15:03