I want to use perl in a bash script to replace some string in a text file with other strings that may contain various special characters (passwords). The variables containig the special characters come from the environment, so I cannot know them.
For example
# pw comes from the environment and I cannot be sure about it's content
pw='%$&/|some!\!smart%(]password'
pw=${pw//:/\\:}
perl -p -e "s:PASSWORD:$pw:" <<< "my pw is: PASSWORD" # this would come from a text file
# yields: my pw is: %PASSWORD/|some!!smart%(]password
Here I use : as a delimiter and escape possible occurences before, which should prevent some errors. But executing this does show that this isn't even remotely working as expected, though. The bash expansion is still messing up the password.
Now my question is: How can I safely take some environment variable and place it somewhere else? What might be a better approach? I could of course replace and escape further characters in the unknown variable but how can I ever be sure if this is enough?
Using the proper ENV special variable:
pw='%$&/|some!\!smart%(]password'
export pw=${pw//:/\\:}
perl -pe 's:PASSWORD:$ENV{pw}:' <<< "my pw is: PASSWORD"
Related
I am trying to use a variable within sed but cant work it out. I have tried
read -p " enter your name" name
sed -i 's/myname/$name/g' file
But unfortunately it just replaces myname with "$name".
Is there an alternative way?
The problem is that the bash shell does not do variable expansion within single quotes. For example:
pax> name=paxdiablo
pax> echo 'Hello, $name, how are you?'
Hello, $name, how are you?
For simple cases like this, you can just use double quotes:
pax> echo "Hello, $name, how are you?"
Hello, paxdiablo, how are you?
Having said that, there are some serious concerns with just using arbitrary data expanded like this. A clever attacker could give a name containing characters that would cause your sed to do things you may not want (via an injection attack):
pax#paxbox$ name='/; e printenv; echo '
pax#paxbox$ echo 'Hello, myname' | sed "s/myname/$name/"
LESSOPEN=| /usr/bin/lesspipe %s
USER=pax
: (lots of other stuff about my environment I don't want people to see)
HOSTTYPE=x86_64
/
Hello,
And it doesn't even have to be clever - anyone entering a name containing / will almost certainly cause your sed to fail.
You should either sanitise your input data or use tools where the scope for attack is greatly reduced.
I'm writing a script in bash that performs a simple transform of a file we'll call storage.config.
Parameters are passed from our automation system (VCAC\AppD) to our action script, which performs the transform using sed.
To keep things simple, I'll use the following example
storage.config - To be transformed
url=jdbc:sqlserver://#myDB
Transform Script
myDB='serverxyz\\instance'
sed -i -e "s,#myDB,$myDB,g" storage.config
I would expect the resulting storage.config to look like this;
url=jdbc:sqlserver://serverxyz\\instance
However, it looks like this instead;
url=jdbc:sqlserver://serverxyz\instance
I've read through the answers on this site, as well as others. And have found a lot of useful information on how to include variable, single vs. double quotes, but nothing on how to retain a double \ in a variable. I'd like to get sed to interpret correctly, rather than type something like;
myDB='serverxyz\\\\instance'
This value will be entered by Solutions Engineers, who might enter improperly as they don't recognize it as a valid SQL instance.
sed is interpreting it correctly.
You are sticking \\ in the replacement as a literal string.
sed doesn't know it was a variable from somewhere else and not just typed out manually.
Escaping it is the answer.
You can do it at expansion time with ${myDB//\\/\\\\} if you want though.
Additionally, as #abesto quite correctly indicated in his answer, you are loosing the doubled slash before sed even sees it. Use single quotes in your assignment to preserve it.
myDB='server\\instance'
The double \ doesn't even get as far as sed. Your shell sees \\, and reads it as "oh, you want a \, because you escaped it". You can try it out like this:
myDB="serverxyz\\instance"
echo "$myDB"
# output: serverxyz\instance
So in conclusion (Thanks to all that responded. Special thanks to #Etan);
myDB='serverxyz\\instance'
sed -i -e "s,#myDB,${myDB//\\/\\\\},g" storage.config
The above code results in the proper translation\transform of my storage.config file. The resulting storage.config is as follows;
url=jdbc:sqlserver://serverxyz\\instance
I've been using Codeigniter for my PHP project and I've been using their session class.
$this->session->userdata('variablename')
I've been having a lot of problems with this so i've decided to use PHP Native session.
$_SESSION['variablename']
This is what I've got so far
perl -p -i -e "s/$this->session->userdata('.*?$SOMEVAR.*?\')/$_SESSION['$1']/g" offer.php
But truth to be told I don't really know what I'm doing.
I would also like to do this on all php files in my project.
Help much appreciated.
The regex should be:
s/\$this->session->userdata\('(.?)'\)/$_SESSION['$1']/g
Issues with the version you posted are mostly with un-escaped characters--you can escape a $ or parenthesis by adding a \ prior to the character. For example, \$this will find the text "$this", while $this will search for the value of the $this variable.
For a more comprehensive look at escapes (and other quick tips), if you have $2, I highly recommend this cheat sheet.
Also, you don't need to use the .*?$SOMEVAR.*? construct you added in there...Perl will automatically capture the result found between the first pair of parentheses and store it in $1, the second set of parentheses gets $2, etc.
When shell quoting is getting complicated, the simplest thing to do is to just put the source into a file. You can still use it as a one-liner. I have used a negative lookahead assertion to make sure that it does not break for escaped single quotes inside the string.
# source file, regex.txt
s/\$this->session->userdata\('(.+?)(?!\\')'\)/\$_SESSION['$1']/g;
Usage:
perl -pi regex.txt yourfile.php
Note that you simply leave out the -e switch. Also note that -i requires a backup extension for Windows, e.g. -i.bak.
I am using following kind of script in my perl script and expecting entry at line 1. I am getting some error as below; any help?
plz ignore perl variable....
Error Messaage -
sed: -e expression #1, char 22: extra characters after command
# Empty file will not work for Sed line number 1
`"Security Concerns Report" > $outputFile`;
`sed '1i\
\
DATE :- $CDate \
Utility accounts with super access:- $LNumOfSupUserUtil \
Users not found in LDAP with super access: - $LNumOfSupUserNonLdap\
' $outputFile > $$`;
`mv $$ $outputFile`;
}
Your immediate problem is that the backslash character is interpreted by Perl inside the backtick operator, as is the dollar character. So your backslash-newline sequence turns into a newline in the shell command that is executed. If you replace these backslashes by \\, you'll go over this hurdle, but you'll still have a very brittle program.
Perl is calling a shell which calls sed. This requires an extra level of quoting for the shell which you are not performing. If your file names and data contain no special characters, you may be able to get away with this, until someone uses a date format containing a ' (among many things that would break your code).
Rather than fix this, it is a lot simpler to do everything in Perl. Everything sed and shells can do, Perl can do almost as easily or easier. It's not very clear from your question what you're trying to do. I'll focus on the sed call, but this may not be the best way to write your program.
If you really need to prepend some text to an existing file, there's a widely-used module on CPAN that already does this well. Use existing libraries in preference to reinventing the wheel. File::Slurp has a prepend_file method just for that. In the code below I use a here-document operator for the multiline string.
use File::Slurp; # at the top of the script with the other use directives
File::Slurp->prepend_file($outputFile, <<EOF);
DATE :- $CDate
Utility accounts with super access:- $LNumOfSupUserUtil
Users not found in LDAP with super access: - $LNumOfSupUserNonLdap
EOF
I'm a noob at bash need to replace the mypassword part of this line in a file
"rpc-password": mypassword
with mynewpassword
I tried
perl -pi -e "s,PASSWORD,${password},g" "${user_conf}"
but it dosen't seem to do anything :(
I can use anything that will work inside a bash script, it dosen't have to be bash or perl.
perl -pi -e 's/mypassword/mynewpassword/g' file
will work
Using a loose regex without keeping backups is a bad idea. Especially if you intend to use dynamic replacement strings. While it may work just fine for something like "mypassword", it will break if someone tries to replace with the password "ass" with "butt":
"rpc-password": mypassword
Would become:
"rpc-pbuttword": butt
The more automation you seek, the more strict you need the regex to be, IMO.
I would anchor the replacement part to the particular configuration line that you seek:
s/^\s*"rpc-password":\s*\K\Q$mypassword\E\s*$/$mynewpassword/
No /g modifier, unless you intend to replace a password several times on the same line. \K will preserve the characters before it. Using \s* liberally will be a safeguard against user-edited configuration files where extra whitespace might have been added.
Also, importantly, you need to quote meta characters in the password. Otherwise a password such as t(foo)? Will also match a single t. In general, it will cause strange mismatches. This is why I added \Q...\E (see perldoc perlre) to the regex, which will allow variable interpolation, but escape meta characters.
You can also use sed for this:
sed -i 's/mypassword/mynewpassword/g' file