Replacing a certain number of characters after a match using sed with {,/ and " - shell

I need to replace whatever is there after \"db_password\":\" up to 16 characters (passwords) with <sensitive>:
data_json: "{\"db_password\":\"qwHLI?mkSrQ=GHU_\"}" => "{\"db_password\":\"BoBBsR9PA]wZ_3AC\"}"
should be
data_json: "{\"db_password\":\"sensitive\"}" => "{\"db_password\":\"sensitive\"}"
I have tried following but not sure how to escape {, \ and ".
sed -E 's/("{\"db_password\":\").{16}/\<sensitive>/'

cat jsonfile
#=> data_json: "{\"db_password\":\"qwHLI?mkSrQ=GHU_\"}" => "{\"db_password\":\"BoBBsR9PA]wZ_3AC\"}"
sed -E 's/("\{\\"db_password\\":\\").{16}/\1sensitive/g' jsonfile
#=> data_json: "{\"db_password\":\"sensitive\"}" => "{\"db_password\":\"sensitive\"}"
You need escape \ too. Also \1 to reference the first pair () matched content.
<> is unnessary here.
Update: without the 16 chars password limitation:
sed -E 's/("\{\\"db_password\\":\\")[^"\]+/\1sensitive/g' jsonfile
#=> data_json: "{\"db_password\":\"sensitive\"}" => "{\"db_password\":\"sensitive\"}"
This will replace password of any passwords. (Well, can't have \ in passwords.)

Related

'grep' a file name, but only show

I have files that are named ACC160-MASTER-201503, ACC160L-MASTER-201503 and IS160-MASTER-201503. I'm basically trying to output the first few letters (in the example, just ACC and IS) and not the numbers. After that I need another grep to only grab up to the - (in the example, ACC160, ACC160L, and IS160).
If this is bash/ksh/zsh/sh/..., just use parameter substitution:
for file in ACC160-MASTER-201503 ACC160L-MASTER-201503 IS160-MASTER-201503; do
alnum=${file%%-*} # remove the first "-" and following chars
alpha=${alnum%%[0-9]*} # remove the first digit and all following chars
echo "$file => $alnum => $alpha"
done
ACC160-MASTER-201503 => ACC160 => ACC
ACC160L-MASTER-201503 => ACC160L => ACC
IS160-MASTER-201503 => IS160 => IS
If you want to get all the filename until the first '-' then grep -oP ".*?(?=-)" should do the trick.
-o is the only-matching option
-P enables Perl syntax
.*? is a reluctant quantifiers, it reads while looking for the next motif in the regex
(?=-) is a lookahead tag: it tells you what to expect (-) after the matching substring

How to wrap words in single quotes using sed script?

I am curious how can I do the following thing with sed: I need to wrap certain two words in single quotes in each line. For example, the following text:
I did it like this:
cat file |sed "s/[^ ][^ ]*/'&'/g"
result:
'the-first-word' '-firstPrameter' 'value' '-secondParameter' 'value' '-thirdParameter' 'value' '-fourthParameter' 'value'
But it is wrapping every word.
It should be like this, skip the first word and wrap only parameter and value:
the-first-word '-firstPrameter value' '-secondParameter value' '-thirdParameter value' '-fourthParameter value'
sed "s/ \([^ ]* [^ ]*\)/ '\\1'/g" file
$cat file.txt
the-first-word -firstPrameter value -secondParameter value -thirdParameter value -fourthParameter value
$sed "s/ \([^ ]* [^ ]*\)/ '\\1'/g" file.txt
the-first-word '-firstPrameter value' '-secondParameter value' '-thirdParameter value' '-fourthParameter value'
In your example, the first word is at the start of the line. Thus, if we quote all words that have a space in front of them, then we will quote all but the first:
sed "s/ \([^ ]\+\)/ '\\1'/g" file
the-first-word '-firstPrameter' 'value' '-secondParameter' 'value' '-thirdParameter' 'value' '-fourthParameter' 'value'
If your sed supports the -r flag (GNU), then we can remove some of those backslashes:
sed -r "s/ ([^ ]+)/ '\\1'/g" file
On Mac OSX, replace -r with -E.

sed append line - how do I get a new line?

I have spent hours on this but can't crack it. I am using sed on OSX .
This is the code:
sed -i.bak "s/^\(\$dokuwiki_hash.*\)$/\1\n '"$date"' => '"$hash"',/" install.php
And the output that I get which is wrong is (see the first line):
$dokuwiki_hash = array(n '2013-03-17' => '7b62b75245f57f122d3e0f8ed7989623',
'2005-09-22' => 'e33223e957b0b0a130d0520db08f8fb7',
'2006-03-05' => '51295727f79ab9af309a2fd9e0b61acc',
'2006-03-09' => '51295727f79ab9af309a2fd9e0b61acc',
'2006-11-06' => 'b3a8af76845977c2000d85d6990dd72b',
'2007-05-24' => 'd80f2740c84c4a6a791fd3c7a353536f',
'2007-06-26' => 'b3ca19c7a654823144119980be73cd77',
'2008-05-04' => '1e5c42eac3219d9e21927c39e3240aad',
'2009-02-14' => 'ec8c04210732a14fdfce0f7f6eead865',
'2009-12-25' => '993c4b2b385643efe5abf8e7010e11f4',
'2010-11-07' => '7921d48195f4db21b8ead6d9bea801b8',
'2011-05-25' => '4241865472edb6fa14a1227721008072',
'2011-11-10' => 'b46ff19a7587966ac4df61cbab1b8b31',
'2012-01-25' => '72c083c73608fc43c586901fd5dabb74',
'2012-09-10' => 'eb0b3fc90056fbc12bac6f49f7764df3',
'2013-04-06' => '7b62b75245f57f122d3e0f8ed7989623',
);
It should be on a new line like below:
$dokuwiki_hash = array(
'2013-03-17' => '7b62b75245f57f122d3e0f8ed7989623',
'2005-09-22' => 'e33223e957b0b0a130d0520db08f8fb7',
'2006-03-05' => '51295727f79ab9af309a2fd9e0b61acc',
'2006-03-09' => '51295727f79ab9af309a2fd9e0b61acc',
'2006-11-06' => 'b3a8af76845977c2000d85d6990dd72b',
'2007-05-24' => 'd80f2740c84c4a6a791fd3c7a353536f',
'2007-06-26' => 'b3ca19c7a654823144119980be73cd77',
'2008-05-04' => '1e5c42eac3219d9e21927c39e3240aad',
'2009-02-14' => 'ec8c04210732a14fdfce0f7f6eead865',
'2009-12-25' => '993c4b2b385643efe5abf8e7010e11f4',
'2010-11-07' => '7921d48195f4db21b8ead6d9bea801b8',
'2011-05-25' => '4241865472edb6fa14a1227721008072',
'2011-11-10' => 'b46ff19a7587966ac4df61cbab1b8b31',
'2012-01-25' => '72c083c73608fc43c586901fd5dabb74',
'2012-09-10' => 'eb0b3fc90056fbc12bac6f49f7764df3',
'2013-04-06' => '7b62b75245f57f122d3e0f8ed7989623',
);
Any help would be greatly appreciated !
Don't use substitute for this, sed has a perfectly good append command for adding a line after the current one, without fiddling around with newline or storage of regex results:
pax> echo '$dokuwiki_hash = array(
'"'"'2013-03-17'"'"' => '"'"'7b62b75245f57f122d3e0f8ed7989623'"'"'
);' | sed '/^\$dokuwiki_hash = /a\ blah '"'"'blah'"'"' blah'
$dokuwiki_hash = array(
blah 'blah' blah
'2013-03-17' => '7b62b75245f57f122d3e0f8ed7989623'
);
The machinations with the quotes are to allow you to put literal single quotes within the command.
Alternatively, you can use double quotes on the outside, you just have to be careful that the shell doesn't interpret your dollar-variables:
pax> echo "\$dokuwiki_hash = array(
'2013-03-17' => '7b62b75245f57f122d3e0f8ed7989623'
);" | sed "/^\$dokuwiki_hash = /a\ blah 'blah' blah"
$dokuwiki_hash = array(
blah 'blah' blah
'2013-03-17' => '7b62b75245f57f122d3e0f8ed7989623'
);
There's also an opposing insert command i for inserting before the current line but it's append you want in this case.
And, if you're having trouble with mixing quote types (perhaps due to an older bash under OSX), you can put the sed commands into a file and use sed -f to run them:
pax> cat qq.sed
/^$dokuwiki_hash = /a\ blah 'blah' blah
pax> echo '$dokuwiki_hash = array(
'"'"'2013-03-17'"'"' => '"'"'7b62b75245f57f122d3e0f8ed7989623'"'"'
);' | sed -f qq.sed
$dokuwiki_hash = array(
blah 'blah' blah
'2013-03-17' => '7b62b75245f57f122d3e0f8ed7989623'
);
That gets around any quoting battles between the shell and sed. If that still doesn't work, see this link, which suggests installing GNU sed instead.
\n is not supported as a newline character in the replacement part of the substitute command of regular sed (only in GNU sed).
For example to prepend a newline to a pattern, instead of
sed 's/pattern/\n&/' file
use
sed 's/pattern/\
&' file
The \ should be the last character on the line.

Bash Sed replace

I'm working in a Zend CRUD generator and I have to replace the word "test" which is in $targetForm file with the form code of each field.
field[0]="foo"
field[1]="bar"
textareafield='$'"acme_en = new Utils_Form_Element_Textarea('acme_en',array('langblock'=>'en', 'isWysiwyg' => true));
"'$'"this->addElement("'$'"acme_en);
"'$'"this->addElement('textarea','acme_fr', array( 'label'=>__('acme'), 'langblock'=>'fr', 'isWysiwyg' => true, 'altLangElem' => "'$'"acme_en));"
for ((i=0; i<${#field[#]}; i++));
do
formfield[$i]=$textareafield
formfield[$i]=${formfield[$i]//acme/${field[$i]}}
echo ${formfield[$i]}
sed -i "s/test/test\n ${formfield[$i]}/" $targetForm
done
The command line says:
$foo_en = new Utils_Form_Element_Textarea('foo_en', array('langblock'=>'en', 'isWysiwyg' => true)); $this->addElement($foo_en); $this->addElement('textarea','foo_fr', array( 'label'=>__('foo'), 'langblock'=>'fr', 'isWysiwyg' => true, 'altLangElem' => $foo_en));
sed: -e expression #1, char 120: unterminated `s' command
$bar_en = new Utils_Form_Element_Textarea('bar_en', array('langblock'=>'en', 'isWysiwyg' => true)); $this->addElement($bar_en); $this->addElement('textarea','bar_fr', array( 'label'=>__('bar'), 'langblock'=>'fr', 'isWysiwyg' => true, 'altLangElem' => $bar_en));
sed: -e expression #1, char 120: unterminated `s' command
Maybe there's a problem with the specials character but I don't know how to solve it.
This error you get very likely has nothing to do with using \n in sed substitution (especially since you mentioned in the comments that you are using GNU sed version 4.2.1).
The real culprit is textareafield which contains a multi-line string.
What happens is that when ${formfield[$i]} gets expanded, your sed command looks like this
sed -i "s/test/test\n line1
line2
line3/"
This is problematic because without terminating lines with a literal \, sed would interpret each line as a complete command in itself, in this case
s/test/test\n line1
which is missing a / at the end, hence the error "unterminated `s' command".
To fix this, what we want is to insert a \ to the end of every line except the last, i.e.
sed -i "s/test/test\n line1\
line2\
line3/"
I got your example to work by adding two lines
for ((i=0; i<${#field[#]}; i++));
do
formfield[$i]=$textareafield
formfield[$i]=${formfield[$i]//acme/${field[$i]}}
formfield[$i]=${formfield[$i]//\;/\;\\}
formfield[$i]=${formfield[$i]%\\}
echo ${formfield[$i]}
sed -i "s/test/test\n ${formfield[$i]}/" $targetForm
done
Since all the lines in textareafield end in ;, I replaced all ; with ;\, then removed the last \ from the last line.
sed does not support \n in the substitution, but you can use a literal newline if you escape it. Also, you need to quote the ' characters. Here is one way of doing it:
for ((i=0; i<${#field[#]}; i++));
do
formfield[$i]=$textareafield
formfield[$i]=${formfield[$i]//acme/${field[$i]}}
sedexpr="${formfield[$i]}"
sedexpr="${sedexpr//\'/\'}"
sedexpr="${sedexpr//
/\\
}"
sed -i "s/test/test\
${sedexpr}/" $targetForm
done
But at this level of complexity you're probably better off switching to something like Python.

Regex to match any character except a backslash

How can i say "all symbols except backslash" in Ruby character class?
/'[^\]*'/.match("'some string \ hello'") => should be nil
Variant with two backslashed doesn't work
/'[^\\]*'/.match("'some string \ hello'") => 'some string \ hello' BUT should be nil
Your problem is not with your regex; you got that right. Your problem is that your test string does not have a backslash in it. It has an escaped space, instead. Try this:
str = "'some string \\ hello'"
puts str #=> 'some string \ hello'
p /'[^\\]*'/.match(str) #=> nil
You need to escape the backslash:
[^\\]*
because backslash is the escape character in regular expressions, thus escaping the closing bracket here.
If you want to verify that the whole string contains non-backslash characters, then you need anchors:
^[^\\]*$
There's actually not a backslash in your string to match against. Try taking a look at just your input:
"'some string \ hello'".length # => 20
"a\ b".length # => 3
The "\ " in double quotes is being escaped into just a space:
irb(main):014:0> " "[0].to_i # => 32
irb(main):015:0> "\ "[0].to_i # => 32
irb(main):016:0> "\ ".size #=> 1
If you want to match no slash, you'll need two, like in your second example, which looks good to me:
/'[^\\]*'/.match("'some string \\ hello'") # => nil
This is relevant to Csharp.. but idk it might help you.
[^\\\\]*
four slashes instead of two.

Resources