Using sed with command-substitution text in the replacement part is not working - sed

I have a CFN with cfn-init to deploy a Apache web server with specified virtual hosts. In the template, I use a AWS::CloudFormation::Init configset to replace local IPs with the Instance's private IP.
config:
packages:...
files:...
services:...
commands:
replacePrivateIP:
cwd: "/etc/httpd/conf"
command: !Sub |
sed -i 's#127.0.0.1#$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)#g' httpd.conf
The sed command works fine outside the CFN template. But in the CFN-init process, it simply replace "127.0.0.1" with the whole $(curl -s http://...) string.
How can I feed the instance private IP correctly into the httpd.conf file through cfn-init?

The command-substitution syntax $(..) does not work when wrapped in single quotes which is as expected in bash or most other shells as they preserve the literal value present inside. For your substitution to happen, put it inside double-quotes as
sed -i 's#127.0.0.1#'"$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)"'#g' httpd.conf
Compare the outputs of echo '$(date)' and echo "$(date)" for a simple example of your case.

Related

Replace string with $ from makefile with sed

I am trying to replace ${dbPassword} in a property file with a password including $ signs.
My command is the following, but I have no idea how to replace this properly.
run: #cat $(FILE_PATH) | sed -i .bak 's/$${dbPassword}/$(VARIABLE_WITH_PWD)/g' $(FILE_PATH)
Let's say my dbPassword is: 123$456$789
With this, I am getting the result: 123${dbPassword}456${dbPassword}789
Three problems:
Target and recipe on the same line. The recipe must be on the next line, indented with a hard tab.
You pass $(FILE_PATH) on stdin, and as a file argument to sed. Remove the cat pipe.
Shell variables (as opposed to make variables) are not substituted inside single quotes.
So you might want to try this instead:
.PHONY: run
run:
sed -i .bak "s/$${dbPassword}/$(VARIABLE_WITH_PWD)/g" $(FILE_PATH)
This assumes you have an environment variable, dbPassword and exported it prior to running make. If that is not the case, please provide your complete makefile.
I also have removed the # so you actually see what command make is executing. There's no point in wearing a blindfold while debugging your makefile.

Multiple mongo commands in kubernetes not working

I am attempting to automate the following series of commands which work correctly into a BASH script:
kubectl exec -it mongo-pod -- bash
mongo DBNAME
db.auth("theUser", "thePw")
db.theCollection.find()
The script I am using is as follows:
#!/bin/bash
kubectl exec -it mongo-pod -- bash -c "mongo DBNAME && /
db.auth("theUser", "thePw") && /
db.theCollection.find()"
I have tried the following:
Executing multiple commands( or from a shell script) in a kubernetes pod
but any commands that are added after the first using & or && are not executed. For example just using "mongo DBNAME" correctly opens the prompt and sets it to the correct db, but adding any other command with && causes all commands to fail with the following:
bash: -c line 0: syntax error near unexpected token 'theUser'
All of the comments are spot on, but at least two things I have the highest confidence I have the answer to:
First, you have the line continuation character wrong; it should be \ and not /. It actually wouldn't even be required if you switched bash into "exit on error" mode, with
kubectl exec -it mongo-pod -- bash -ec "mongo DBNAME
echo 'this command only runs if mongo exits a-ok'
exit 1
and this never will run
"
However, the other mistake is around the quoting characters used: if you have bash -c " then you must either use the single-quote for the interior string literals, or escape them with \". You can actually see what I'm talking about by looking at the syntax highlighting of the shell snippet in your question. Observe that the string literal is red, but then the text theUser as well as thePw are both black -- that's because they are outside the string literal since the string stopped at the first " it encountered -- the one present in db.auth("
It is almost always the case that you'll want to use single quotes when invoking bash remotely like that, for several reasons but the most relevant is that you can then use db.auth("something") without having to unnecessarily escape the double quotes.
Since mongo (like many interpreters such a node and python) wants you to either type in it interactively, provide the input on its "standard input", or give it a local file containing commands, you will want to change the invocation to one of those strategies depending on your needs.
A very convenient way of redirecting standard input without having to use echo or printf and its associated quoting hell is to use what are called "here documents" (abbreviated "heredocs") in bash:
kubectl exec -it mongo-pod -- bash -ec 'mongo DBNAME<<"FOO"
db.auth("theUser", "thePw")
printjson(db.theCollection.find())
FOO
'
That causes bash to transmit almost all characters between the two "heredoc delimiters" to the standard input of the command. If you quote the delimiter, as I have with the [arbitrary] word FOO, then the contents are not subject to variable expansion, command interpolation, etc, which can be one more mechanism to avoid backtick and dollarsign weirdness.

Sed command not working on a different server

Sed command is not replacing the contents, does so on a replicated server. Both are runnin ksh.
sed -i '/NewValue/s/NewValue/SAPROD/g' AVL_5002760241.GMF
This works properly. Replaced all NewValue to SAPROD.
sed -i '/SAPROD.*/s/SAPROD/NewValue/g' AVL_5002760241.GMF
This also works correctly. Replaced all SAPROD to to NewValue
sed -i '/NewValue.*500175852/s/NewValue/SAPROD/g' AVL_5002760241.GMF
This does not do any substitution.
Run this way (LANG=C some command) LANG will only be changed for the sed command, not for the surrounding shell. Works for all environment variables.
(Quoting #Wintermute to make a Q/A pair.)

Strange sed command

I was trying to install docker in Ubuntu, and following the instructions I have come across a very strange sed command which I do not understand (this seems to be used to set-up bash autocompletion for docker):
sudo sed -i '$acomplete -F _docker docker' /etc/bash_completion.d/docker.io
What is that command doing? The -i command means in-place editing, but what does the $acomplete -F _docker docker mean? The $ is matching the last line, but what is it doing? I do not even recognize any sed command there! For example, a substitution command would look like:
$s/in/out/
Could somebody explain that expression for me?
It appends complete -F _docker docker to the file.
From sed's manual:
a \
text Append text, which has each embedded newline preceded by a backslash.

sed+text on a specific line after an IP

I have the following line in my proftpd log (line 78 to be precise)
Deny from 1.2.3.4
I also have a script which rolls through my logs for people using brute force attacks and then stores their IP (ready for a black listing). What i'm struggling with is inserting (presume with sed) at the end of that specific line - this is what I've got so far:
sed "77i3.4.5.6" /opt/etc/proftpd.conf >> /opt/etc/proftpd.conf
Now one would presume this would work perfectly, however it actually does the following (lines 77 through 78):
3.4.5.6
Deny from 1.2.3.4
I suspect this is due to my dated version of sed, are there any other ways of acheiving the same thing? Also the >> causes the config to be duplicated at the end of the fole (again i'm sure this is a limitation of my version of sed). This is running a homebrew linux kernel on my nas. Sed options below:
root#NAS:~# sed BusyBox v1.7.0
(2009-04-29 19:12:57 JST) multi-call
binary
Usage: sed [-efinr] pattern [files...]
Options:
-e script Add the script to the commands to be executed
-f scriptfile Add script-file contents to the
commands to be executed
-i Edit files in-place
-n Suppress automatic printing of pattern space
-r Use extended regular expression syntax
If no -e or -f is given, the first
non-option argument is taken as the
sed script to interpret. All remaining
arguments are names of input files; if
no input files are specified, then the
standard input is read. Source files
will not be modified unless -i option
is given.
Cheers for your help guys.
This has nothing to do with the version of sed; this is just plain old Doing It Wrong.
sed -i '77s/$/,3.4.5.6/' /opt/etc/proftpd.conf