Variable expansion and escaped characters - variables

In PowerShell, you can expand variables within strings as shown below:
$myvar = "hello"
$myvar1 = "$myvar`world" #without the `, powershell would look for a variable called $myvarworld
Write-Host $myvar1 #prints helloworld
The problem I am having is with escaped characters like nr etc, as shown below:
$myvar3 = "$myvar`albert"
Write-Host $myvar3 #prints hellolbert as `a is an alert
also the following doesnt work:
$myvar2 = "$myvar`frank" #doesnt work
Write-Host $myvar2 #prints hellorank.
Question:
How do I combine the strings without worrying about escaped characters when I am using the automatic variable expansion featurie?
Or do I have to do it only this way:
$myvar = "hello"
$myvar1 = "$myvar"+"world" #using +
Write-Host $myvar1
$myvar2 = "$myvar"+"frank" #using +

This way is not yet mentioned:
"$($myvar)frank"
And this:
"${myvar}frank"

This seems kind of kludgy, but as another option, you can add a space and a backspace:
$myvar = "hello"
$myvar1 = "$myvar `bworld"
$myvar1

Yet another option is to wrap your variable expression in a $():
$myvar3 = "$($myvar)albert"
Write-Host $myvar3

One other option is through the format operator:
"{0}world" -f $myvar

Another option is a double-quoted here-string:
$myvar = "Hello"
$myvar2 = #"
$myvar$("frank")
"#

Related

POWERSHELL: making a literal string out of a expanded string

I have a string that I build from a couple sources to do matching with later, the short of my code so far is:
$temp = "some\good"
if("some text" -match $temp)
My representation of $temp is simple but actually it is built, this is an example of how it can get built, so no, in this case changing " for ' to pass a literal to $temp won't work. If I hard code the if to use a literal string version of $temp, it works so its a matter of converting the value in $temp to a literal string.
I get the following error when I run my code:
parsing "some\good" - Unrecognized escape sequence \g.
At [not important]
+ if($temp2 -match $temp)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException
"Converting to literal string" won't help you here. String is a string, it only matters how it's being used, i.e. if the content is being interpreted in some way.
-match operates on regex, and that's it, you can't change that, you'd have to escape every all characters that have a meaning in regex.
But you can use select-string instead, which has a switch for simple matching:
$text = "some text"
$patt = "some\good"
if (($text | Select-String -SimpleMatch -Pattern $patt | Measure-Object).count -gt 0) {
Write-Host "match"
} else {
Write-Host "nomatch"
}

Address Variables with PowerShell and Import-CSV foreach-loop

Input file:
"Server1","lanmanserver"
"Server2","lanmanserverTest"
Program
$csvFilename = "D:\Scripts\ServerMonitorConfig.csv"
$csv = Import-Csv $csvFilename -Header #("ServerName","ServiceName")
foreach ($line in $csv) {
Write-Host "ServerName=$line.ServerName ServiceName=$line.ServiceName"
}
What I want:
Server-Name=Server1 ServiceName=lanmanserver
Server-Name=Server2 ServiceName=lanmanserverT
What I'm getting:
ServerName=#{ServerName=Server1; ServiceName=lanmanserver}.ServerName
ServiceName=#{ServerName=Server1; ServiceName=lanmanserver}.ServiceN
ame ServerName=#{ServerName=Server2;
ServiceName=lanmanserverTest}.ServerName
ServiceName=#{ServerName=Server2; ServiceName=lanmanserverTest}.
ServiceName
I really don't care if the Headers come from the first row of the CSV or not, I'm flexible there.
You usually see subexpressions or format strings used to solve that:
Subexpression:
Write-Host "ServerName=$($line.ServerName) ServiceName=$($line.ServiceName)"
Format string:
Write-Host ('ServerName={0} ServiceName={1}' -f $line.ServerName,$line.ServiceName)

Perl replace with variable

I'm trying to replace a word in a string. The word is stored in a variable so naturally I do this:
$sentence = "hi this is me";
$foo=~ m/is (.*)/;
$foo = $1;
$sentence =~ s/$foo/you/;
print $newsentence;
But this doesn't work.
Any idea on how to solve this? Why this happens?
Perl lets you interpolate a string into a regular expression, as many of the answers have already shown. After that string interpolation, the result has to be a valid regex.
In your original try, you used the match operator, m//, that immediately tries to perform a match. You could have used the regular expression quoting operator in it's place:
$foo = qr/me/;
You can either bind to that directory or interpolate it:
$string =~ $foo;
$string =~ s/$foo/replacement/;
You can read more about qr// in Regexp Quote-Like Operators in perlop.
You have to replace the same variable, otherwise $newsentence is not set and Perl doesn't know what to replace:
$sentence = "hi this is me";
$foo = "me";
$sentence =~ s/$foo/you/;
print $sentence;
If you want to keep $sentence with its previous value, you can copy $sentence into $newsentence and perform the substitution, that will be saved into $newsentence:
$sentence = "hi this is me";
$foo = "me";
$newsentence = $sentence;
$newsentence =~ s/$foo/you/;
print $newsentence;
You first need to copy $sentence to $newsentence.
$sentence = "hi this is me";
$foo = "me";
$newsentence = $sentence;
$newsentence =~ s/$foo/you/;
print $newsentence;
Even for small scripts, please 'use strict' and 'use warnings'. Your code snippet uses $foo and $newsentence without initialising them, and 'strict' would have caught this. Remember that '=~' is for matching and substitution, not assignment. Also be aware that regexes in Perl aren't word-bounded by default, so the example expression you've got will set $1 to 'is me', the 'is' having matched the tail of 'this'.
Assuming you're trying to turn the string from 'hi this is me' to 'hi this is you', you'll need something like this:
my $sentence = "hi this is me";
$sentence =~ s/\bme$/\byou$/;
print $sentence, "\n";
In the regex, '\b' is a word boundary, and '$' is end-of-line. Just doing 's/me/you/' will also work in your example, but would probably have unintended effects if you had a string like 'this is merry old me', which would become 'this is yourry old me'.

Dynamic variable and value assignment in powershell

How can I declare variables and assign values to them at run time.
Reason: I am fetching these variables values from sql server and these variable values are configurable in nature
Code which I have tried till now
[array]$varArray = #($($ServerName),$($HostName))
foreach($varname in $varArray)
{
$varname = "some test value"
}
Write-Host $ServerName
Write-Host $HostName
The simplest way of using dynamically named variables would be a dictionary:
$vars = #{} # create empty dictionary
# add key/value pairs to dictionary:
$vars["foo"] = 23
$vars["bar"] = "foobar"
$vars["baz"] = Get-Content C:\sample.txt
Another way would be to declare variables on the fly:
$name = "foo"
$value = "bar"
New-Variable $name $value
echo $foo
Or you could create a custom object and add properties as Kyle C suggested. That approach is similar to a dictionary, although technically different.
You could try adding a NoteProperty to the object.
$varname | Add-Member -type NoteProperty -name TestProperty -value "some test value" -PassThru
Also see this for what types of objects you can add a member to: What objects are suitable for Add-Member?

Break down JSON string in simple perl or simple unix?

ok so i have have this
{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}
and at the moment i'm using this shell command to decode it to get the string i need,
echo $x | grep -Po '"utterance":.*?[^\\]"' | sed -e s/://g -e s/utterance//g -e 's/"//g'
but this only works when you have a grep compiled with perl and plus the script i use to get that JSON string is written in perl, so is there any way i can do this same decoding in a simple perl script or a simpler unix command, or better yet, c or objective-c?
the script i'm using to get the json is here, http://pastebin.com/jBGzJbMk and if you want a file to use then download http://trevorrudolph.com/a.flac
How about:
perl -MJSON -nE 'say decode_json($_)->{hypotheses}[0]{utterance}'
in script form:
use JSON;
while (<>) {
print decode_json($_)->{hypotheses}[0]{utterance}, "\n"
}
Well, I'm not sure if I can deduce what you are after correctly, but this is a way to decode that JSON string in perl.
Of course, you'll need to know the data structure in order to get the data you need. The line that prints the "utterance" string is commented out in the code below.
use strict;
use warnings;
use Data::Dumper;
use JSON;
my $json = decode_json
q#{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}#;
#print $json->{'hypotheses'}[0]{'utterance'};
print Dumper $json;
Output:
$VAR1 = {
'status' => 0,
'hypotheses' => [
{
'utterance' => 'hello how are you',
'confidence' => '0.96311796'
}
],
'id' => '7aceb216d02ecdca7ceffadcadea8950-1'
};
Quick hack:
while (<>) {
say for /"utterance":"?(.*?)(?<!\\)"/;
}
Or as a one-liner:
perl -lnwe 'print for /"utterance":"(.+?)(?<!\\)"/g' inputfile.txt
The one-liner is troublesome if you happen to be using Windows, since " is interpreted by the shell.
Quick hack#2:
This will hopefully go through any hash structure and find keys.
my $json = decode_json $str;
say find_key($json, 'utterance');
sub find_key {
my ($ref, $find) = #_;
if (ref $ref) {
if (ref $ref eq 'HASH' and defined $ref->{$find}) {
return $ref->{$find};
} else {
for (values $ref) {
my $found = find_key($_, $find);
if (defined $found) {
return $found;
}
}
}
}
return;
}
Based on the naming, it's possible to have multiple hypotheses. The prints the utterance of each hypothesis:
echo '{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}' | \
perl -MJSON::XS -n000E'
say $_->{utterance}
for #{ JSON::XS->new->decode($_)->{hypotheses} }'
Or as a script:
use feature qw( say );
use JSON::XS;
my $json = '{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}';
say $_->{utterance}
for #{ JSON::XS->new->decode($json)->{hypotheses} };
If you don't want to use any modules from CPAN and try a regex instead there are multiple variants you can try:
# JSON is on a single line:
$json = '{"other":"stuff","hypo":[{"utterance":"hi, this is \"bob\"","moo":0}]}';
# RegEx with negative look behind:
# Match everything up to a double quote without a Backslash in front of it
print "$1\n" if ($json =~ m/"utterance":"(.*?)(?<!\\)"/)
This regex works if there is only one utterance. It doesn't matter what else is in the string around it, since it only searches for the double quoted string following the utterance key.
For a more robust version you could add whitespace where necessary/possible and make the . in the RegEx match newlines: m/"utterance"\s*:\s*"(.*?)(?<!\\)"/s
If you have multiple entries for the utterance confidence hash/object, changing case and weird formatting of the JSON string try this:
# weird JSON:
$json = <<'EOJSON';
{
"status":0,
"id":"an ID",
"hypotheses":[
{
"UtTeraNcE":"hello my name is \"Bob\".",
"confidence":0.0
},
{
'utterance' : 'how are you?',
"confidence":0.1
},
{
"utterance"
: "
thought
so!
",
"confidence" : 0.9
}
]
}
EOJSON
# RegEx with alternatives:
print "$1\n" while ( $json =~ m/["']utterance["']\s*:\s*["'](([^\\"']|\\.)*)["']/gis);
The main part of this RegEx is "(([^\\"]|\\.)*)". Description in detail as extended regex:
/
["'] # opening quotes
( # start capturing parentheses for $1
( # start of grouping alternatives
[^\\"'] # anything that's not a backslash or a quote
| # or
\\. # a backslash followed by anything
) # end of grouping
* # in any quantity
) # end capturing parentheses
["'] # closing quotes
/xgs
If you have many data sets and speed is a concern you can add the o modifier to the regex and use character classes instead of the i modifier. You can suppress the capturing of the alternatives to $2 with clustering parenthesis (?:pattern). Then you get this final result:
m/["'][uU][tT][tT][eE][rR][aA][nN][cC][eE]["']\s*:\s*["']((?:[^\\"']|\\.)*)["']/gos
Yes, sometimes perl looks like a big explosion in a bracket factory ;-)
Just stubmled upon another nice method of doing this, i finaly found how to acsess the Mac OS X JavaScript engine form commandline, heres the script,
alias jsc='/System/Library/Frameworks/JavaScriptCore.framework/Versions/A/Resources/jsc'
x='{"status":0,"id":"7aceb216d02ecdca7ceffadcadea8950-1","hypotheses":[{"utterance":"hello how are you","confidence":0.96311796}]}'
jsc -e "print(${x}['hypotheses'][0]['utterance'])"
Ugh, yes i came up with another answer, im strudying python and it reads arrays in both its python format and the same format as a json so, i jsut made this one liner when your variable is x
python -c "print ${x}['hypotheses'][0]['utterance']"
figured it out for unix but would love to see your perl and c, objective-c answers...
echo $X | sed -e 's/.*utterance//' -e 's/confidence.*//' -e s/://g -e 's/"//g' -e 's/,//g'
:D
shorter copy of the same sed:
echo $X | sed -e 's/.*utterance//;s/confidence.*//;s/://g;s/"//g;s/,//g'