LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   add literal string with simple and double quotes to a file (https://www.linuxquestions.org/questions/programming-9/add-literal-string-with-simple-and-double-quotes-to-a-file-4175675574/)

vincix 05-20-2020 04:48 AM

add literal string with simple and double quotes to a file
 
I'm trying to add the following string to a file:
Code:

sed 's|\$MYSQL_PASSWORD|'"$MYSQL_PASSWORD"'|'
I'm using the simple and double quote syntax so that sed would use the MYSQL_PASSWORD variable (in the second part; the first part is literally $MYSQL_PASSWORD) when sed is run in the file I'm trying to add the line to.

What I've tried to far is:
Code:

echo sed 's|\$MYSQL_PASSWORD|'"\$MYSQL_PASSWORD"'|' > file
But unfortunately it drops the quote altogether:
Code:

sed s|\$MYSQL_PASSWORD|$MYSQL_PASSWORD|
Somewhat closer is:
Code:

echo sed 's|\$MYSQL_PASSWORD|'"'"\$MYSQL_PASSWORD"'"'|'
But this drops the double quotes:
Code:

sed s|\$MYSQL_PASSWORD|'$MYSQL_PASSWORD'|
This is becoming a little bit retarded, so if there are more elegant solutions, I'm looking forward to it :)

Ok, I was actually able to find a horrible solution:
Code:

echo sed \''s|\$MYSQL_PASSWORD|'"'\""\$MYSQL_PASSWORD"'"\"'|'\'
But the question remains: is there any other way to achieve this?
Thanks!

pan64 05-20-2020 05:06 AM

that can be quite tricky. I don't know how did you check if the result is ok
Code:

TEXT="sed 's|\$MYSQL_PASSWORD|${MYSQL_PASSWORD}|'"
echo ">${TEXT}<"

would be probably the first step.
If that works you can safely redirect it into file too.

vincix 05-20-2020 05:21 AM

Actually I made a mistake in the final result. It should have been:
Code:

echo sed \''s|\$MYSQL_PASSWORD|'"'\""\$MYSQL_PASSWORD\""'"'|'\'
I had misplaced the \ " (if I write \ " together, then the backslash is removed from the post, because it's interpreted as an escape character! :D)
I tested it by simply redirecting it into the file and it worked as expected:
Code:

root@oms:~# echo sed \''s|\$MYSQL_PASSWORD|'"'\""\$MYSQL_PASSWORD\""'"'|'\' > file
root@oms:~# cat file
sed 's|\$MYSQL_PASSWORD|'"$MYSQL_PASSWORD"'|'


The problem with this solution
Code:

TEXT="sed 's|\$MYSQL_PASSWORD|${MYSQL_PASSWORD}|'"
is that sed interprets the ${MYSQL_PASSWORD} literally, because of the simple quotes. This is why I was trying to use '"$MYSQL_PASSWORD"' (so between simple + double quotes; so I'm escaping the bash variable that way and sed will replace it with the value of the variable, instead of the literal name).

Can you explain what the meaning of the angle brackets in echo ">${TEXT}<" is?

shruggy 05-20-2020 05:37 AM

Your first version should work with a HERE document:
Code:

cat <<EOF >file
sed 's|\$MYSQL_PASSWORD|'"\$MYSQL_PASSWORD"'|'
EOF


ntubski 05-20-2020 05:57 AM

Quote:

Originally Posted by shruggy (Post 6125269)
Your first version should work with a HERE document:
Code:

cat <<EOF >file
sed 's|\$MYSQL_PASSWORD|'"\$MYSQL_PASSWORD"'|'
EOF


You need to use
Code:

cat <<'EOF' > file
sed 's|\$MYSQL_PASSWORD|'"\$MYSQL_PASSWORD"'|'
EOF

Note the quotes around EOF.

https://www.gnu.org/software/bash/ma...Here-Documents
Quote:

If any part of word is quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion

shruggy 05-20-2020 06:09 AM

^ With quotes around EOF you don't need to escape $ in the replacement string:
Code:

cat <<'EOF' > file
sed 's|\$MYSQL_PASSWORD|'"$MYSQL_PASSWORD"'|'
EOF


pan64 05-20-2020 06:13 AM

So your problem is that the password itself contains something which can be interpreted by sed.
You cannot protect it that way there is no fool-proof solution. You need to process the password string itself to escape all the suspicious chars.

> and < are just markers to see what is "inside". Nothing else.

shruggy 05-20-2020 06:49 AM

I assume the file you're writing your sed expression to is a shell script. A reasonably recent bash should have a nice facility to cope with the problem pan64 describes in form of ${var@Q}. From the Bash Reference Manual:
Quote:

${parameter@operator}
The expansion is either a transformation of the value of parameter or information about parameter itself, depending on the value of operator. Each operator is a single letter:

Q
The expansion is a string that is the value of parameter quoted in a format that can be reused as input.


pan64 05-20-2020 09:23 AM

Quote:

Originally Posted by shruggy (Post 6125289)
I assume the file you're writing your sed expression to is a shell script. A reasonably recent bash should have a nice facility to cope with the problem pan64 describes in form of ${var@Q}. From the Bash Reference Manual:

It is something new, somewhere bash 4.4 was implemented.

vincix 05-24-2020 07:04 AM

I wanted to restrict the thread only to this particular problem without giving the bigger context, but now the context has become much more relevant.
The point was to do something somewhat intentionally dumb, that is to say, to change an existing docker-entrypoint from an official docker image (of php-apache) through an additional Dockerfile, where I'd run the sed commands.
The here document would have been a great solution under normal circumstances, and it hadn't occurred to me anyway, but unfortunately it doesn't work in Dockerfile :)

What I did eventually (which I find much more sensible) was to actually copy only the entrypoint from github, add the sed lines that would replace the php configuration settings, and then copy it into the new image, ensuring, of course, that it has execution permissions (being an entrypoint).

@pan64
The issue with this: TEXT="sed 's|\$MYSQL_PASSWORD|${MYSQL_PASSWORD}|'" is that sed is not going to interpret the bash variable as it is, regardless of what the variable contains. This is why it needs to be escaped with '"${MYSQL_PASSWORD}"'. What the actual value of the variable is, is indeed a problem in itself and needs to be dealt with carefully, I agree, sure. That's why I chose a longer string (length of 40-50 characters) but with standard characters, as it were.


Anyway, thanks for the help, I've come away with lots of interesting information! :)

pan64 05-24-2020 07:57 AM

sed will never be able to use bash variables, that is a different language.
https://stackoverflow.com/questions/...itution-in-sed
If you wish to do that you need to use perl/awk/python/... something, which can handle environment variables properly.

vincix 05-24-2020 08:00 AM

Ok, so what about this?
Code:

root@kube:~# var=crap
root@kube:~# echo "stuff" > file.txt
root@kube:~# sed 's/stuff/'"$var"'/' file.txt
crap


pan64 05-24-2020 08:14 AM

In that case the shell will evaluate $var and will pass the result to sed. As always, the command evaluated first (before execution). You can check it by executing set -x (before executing your sed)
Code:

$ set -x
$ var=cap
+ var=cap
$ echo "stuff" > file.txt
+ echo stuff
$ sed 's/stuff/'"$var"'/' file.txt
+ sed s/stuff/cap/ file.txt
cap

black was entered
blue was actually executed (after evaluation)
green is the result

Also [re]read the link I posted.

vincix 05-24-2020 08:17 AM

Ok, I see what you mean (I also hadn't read the link entirely before answering), but that works for all intents and purposes. And that's the most important thing, so that's more of a theoretical problem (yes, not necessarily, because it depends on what the variable contains, but I've already cleared that up). There's no point in switching to another tool when doing such substitutions - they are being used widely.

pan64 05-24-2020 08:22 AM

the problem is when the variable contains something which can be interpreted by sed. And (if the content of the variable is unpredictable) this substitution is just unreliable.


All times are GMT -5. The time now is 06:31 AM.