What is => mean in my bash script - bash

I have this line in a bash script and I can't figure out what the "=>" means? I don't think it means equal to or greater than but maybe it does. Thoughts?
"echo '\"postgres\" => { \"archive_timeout\" => 300, \"backup\" => 1, \"base_backup_interval\" => 3600, \"restore\" => 1 },' >> /tmp/user_data.config\n",

It doesn't mean anything, because it's inside a string. Consider:
$ echo 'foo'
foo
$ echo 'foo => bar'
foo => bar
The => doesn't have any significance; it's just part of the string that echo writes to its output.
In the case of your code, the echo command and its string argument are followed by >> /tmp/user_data.config, which just means that the output will be appended to the user_data.config file. Like so:
$ touch /tmp/out.txt
$ echo 'foo => bar' >> /tmp/out.txt
$ echo 'baz => qux' >> /tmp/out.txt
$ cat /tmp/out.txt
foo => bar
baz => qux

The => is part of the string that is being echo'd. Try running the command (without the " at the beginning and the \n", at the end) in BASH and you'll see it just echoes the string and appends it to /tmp/user_data.config
$ echo '\"postgres\" => { \"archive_timeout\" => 300, \"backup\" => 1, \"base_backup_interval\" => 3600, \"restore\" => 1 },' >> /tmp/user_data.config
$ cat /tmp/user_data.config
\"postgres\" => { \"archive_timeout\" => 300, \"backup\" => 1, \"base_backup_interval\" => 3600, \"restore\" => 1 },

Related

How to eval a shell script to a Ruby hash?

I have this shell script in a file named a.sh:
export A='a'
export B=b
export C=1
export D=$USER # say $USER is root
There are some other similar files b.sh, c.sh, etc.
I need to read the shell file, say a.sh, from ruby script and convert it to a Ruby hash:
{ 'A' => 'a', 'B' => 'b', 'C' => 1, 'D' => 'root' }
How to achieve that?
If you have run the bash script prior to the ruby one, you can get doing something like this:
Hash[([ 'A', 'B', 'C', 'D' ] & ENV.keys).map {|x| [x, ENV[x]] }]
where array [ 'A', 'B', 'C', 'D' ] contains valid variable names to create the Hash.
If you need to parse the bash script in ruby, do as follows:
vars = {}
IO.read('shell.sh').each do| line |
if line =~ /^export\s([A-Za-z_][A-Za-z_0-9]*)=\s*(?:['"]([^'"]*)['"]|(.*))\s*$/
(name, value) = [ $1, $2 || $3 ]
value.gsub!( /\$(?:([A-Za-z_][A-Za-z_0-9]*)|{([^{}]+)})/ ) do| match |
ENV[ match[1..-1] ]
end
vars[ name ] = value.gsub(/#.*/, '').strip
end
end
vars
# => {"A"=>"a", "B"=>"b", "C"=>"1", "D"=>"malo"}

Chaining sed statements

I'm running a dozen of sed commands for each Capistranio deploy and I was wondering, if it's possible to chain them into 1 single sed command, instead of firing dozens at the server.
task :taskname do
{:'foo' => foo, :'bar' => bar, :'foobar' => foobar, :'fubar' => fubar }.each do |search, replace|
run "sed -i 's/#{search}/#{replace}/' file.ext"
end
end
sed natively accepts a dozen of patterns (if you for some reason prefer sed):
{:foo => foo, :bar => bar, :foobar => foobar, :fubar => fubar}.inject("") do |acc, k, v|
acc += " -e 's/#{k}/#{v}'"
end
run "sed #{acc} file.ext"
Does mudasobwa's code work? With my Ruby (v1.9.3), it has to be:
acc = {:foo => foo, :bar => bar, :foobar => foobar, :fubar => fubar}.inject("") do |m, p|
m + " -e 's/#{p[0]}/#{p[1]}'"
end
run "sed #{acc} file.ext"

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.

Is there a bug in Ruby lookbehind assertions (1.9/2.0)?

Why doesn't the regex (?<=fo).* match foo (whereas (?<=f).* does)?
"foo" =~ /(?<=f).*/m => 1
"foo" =~ /(?<=fo).*/m => nil
This only seems to happen with singleline mode turned on (dot matches newline); without it, everything is OK:
"foo" =~ /(?<=f).*/ => 1
"foo" =~ /(?<=fo).*/ => 2
Tested on Ruby 1.9.3 and 2.0.0.
See it on Rubular
EDIT: Some more observations:
Adding an end-of-line anchor doesn't change anything:
"foo" =~ /(?<=fo).*$/m => nil
But together with a lazy quantifier, it "works":
"foo" =~ /(?<=fo).*?$/m => 2
EDIT: And some more observations:
.+ works as does its equivalent {1,}, but only in Ruby 1.9 (it seems that that's the only behavioral difference between the two in this scenario):
"foo" =~ /(?<=fo).+/m => 2
"foo" =~ /(?<=fo).{1,}/ => 2
In Ruby 2.0:
"foo" =~ /(?<=fo).+/m => nil
"foo" =~ /(?<=fo).{1,}/m => nil
.{0,} is busted (in both 1.9 and 2.0):
"foo" =~ /(?<=fo).{0,}/m => nil
But {n,m} works in both:
"foo" =~ /(?<=fo).{0,1}/m => 2
"foo" =~ /(?<=fo).{0,2}/m => 2
"foo" =~ /(?<=fo).{0,999}/m => 2
"foo" =~ /(?<=fo).{1,999}/m => 2
This has been officially classified as a bug and subsequently fixed, together with another problem concerning \Z anchors in multiline strings.

Succinct way in Ruby to manipulate this string

Sometimes I like learning how to do things the "Ruby" way. I was wondering - what is the most succinct, yet readable way to take a string such as:
foo-bar
and manipulate it to read:
Foo Bar
"foo-bar".split("-").map(&:capitalize).join(" ")
"foo-bar".gsub(/\b(\w)/){|m| m.capitalize}.sub '-', ' '
>> p "foo-bar".scan(/\w+/).map(&:capitalize).join(" ")
"Foo Bar"
=> "Foo Bar"
>> p "foo---bar".scan(/\w+/).map(&:capitalize).join(" ")
"Foo Bar"
=> "Foo Bar"
>> p "foo 123 bar".scan(/\w+/).map(&:capitalize).join(" ")
"Foo 123 Bar"
=> "Foo 123 Bar"
string = "foo-bar"
"foo-bar".split("-").map(&:capitalize).join(" ") # edited to because former answer was not optimal

Resources