How to combine CLI arguments as variables within a perl script - perl

I am trying to write a script that basically executes a cli command like:
snmpget -v 1 -c xxxxxx-Ovq xx.xx.xx.xxx .1.3.6.1.2.1.1.8.0
where xxxxx is a password and xx.xx.xx.xxx and IP that normally returns:
49:22:12:15.00
My script is:
#!/usr/local/bin/perl
#snmpget -v 1 -c xxxxx -Ovq xx.xx.xx.xxx .1.3.6.1.2.1.1.8.0
$SNMP_GET_CMD = "snmpget -v1 -c xxxxx-Ovq";
$SNMP_TARGET = "xx.xx.xx.xxx";
my $sysORLastChange = '${SNMP_GET_CMD} ${SNMP_TARGET} .1.3.6.1.2.1.1.8.0';
chomp($sysORLastChange);
print("${SNMP_TARGET} as an Input Line Reading of ${sysORLastChange}\n");
and the output is:
xx.xx.xx.xxx as an Input Line Reading of ${SNMP_GET_CMD} ${SNMP_TARGET} .1.3.6.1.2.1.1.8.0
It should return the following:
xx.xx.xx.xxx as an Input Line Reading of 49:22:12:15.00
Is there any problem with the syntax i used in the script?

In Perl, use double-quotes to interpolate another variable into a string. When you define $sysORLastChange using other variables within a single-quoted string like this:
my $sysORLastChange = '${SNMP_GET_CMD} ${SNMP_TARGET} .1.3.6.1.2.1.1.8.0';
...the string is being assigned verbatim (ie. the inner variables aren't being expanded).
To correct this, assign to the variable using double-quotes, which will interpolate the inner variables into their values:
my $sysORLastChange = "${SNMP_GET_CMD} ${SNMP_TARGET} .1.3.6.1.2.1.1.8.0";
If you want to actually execute the string, you can use the qx() operator, aka the "backtick" style quotes:
my $sysORLastChange = qx(${SNMP_GET_CMD} ${SNMP_TARGET} .1.3.6.1.2.1.1.8.0);
# or...
my $sysORLastChange = `${SNMP_GET_CMD} ${SNMP_TARGET} .1.3.6.1.2.1.1.8.0`;
See Perl Quote and Quote-like Operators in perlop.

Related

Pass string value having space to another powershell file

I have a powershell script which calls another powershell file passing a string argument.
param (
[string]$strVal = "Hello World"
)
$params = #{
message = "$strVal"
}
$sb = [scriptblock]::create(".{$(get-content $ps1file -Raw)} $(&{$args} #params)")
Somehow the script passes message variable without double quotes so the powershell file receives only the first part of the message variable (before space) i.e. "Hello".
How can I pass the strVal variable with space (i.e. "Hello World")?
A double quote pair signals PowerShell to perform string expansion. If you want double quotes to output literally, you need to escape them (prevent expansion) or surround them with single quotes. However, a single quote pair signals PowerShell to treat everything inside literally so your variables will not interpolate. Given the situation, you want string expansion, variable interpolation, and literal double quotes.
You can do the following:
# Double Double Quote Escape
#{message = """$strVal"""}
Name Value
---- -----
message "Hello World"
# Backtick Escape
#{message = "`"$strVal`""}
Name Value
---- -----
message "Hello World"
Quote resolution works from left to right, which means the leftmost quote type takes precedence. So '"$strVal"' will just print everything literally due to the outside single quote pair. "'$strVal'" will print single quotes and the value of $strVal.

How can I extract first and last line from multiple text blocks separated with new line?

I have a file containing multiple tests with detailed action written one beneath another. All test blocks are separated one from another by new line. I want to extract only first and last line from the all blocks and put it on one line for each block into a new file. Here is an example:
input.txt:
[test1]
duration
summary
code=
Results= PASS
[test2]
duration
summary=x
code=
Results=FAIL
.....
[testX]
duration
summary=x
code=
Results= PASS
output.txt should be sometime like this:
test1 PASS
test2 FAIL
...
testX PASS
eg2:
[Linux_MP3Enc_xffv.2_Con_37_003]
type = testcase
summary = MP3 encoder test
ActionGroup[Linux_Enc] = PASS
ActionGroup[Linux_Playb] = PASS
ActionGroup[Linux_Pause_Resume] = PASS
ActionGroup[Linux_Fast_Seek] = PASS
Duration = 230.607398987 s
Total_Result = PASS
[Composer__vtx_007]
type = testcase
summary = composer
Background[0xff000000] = PASS
Background[0xffFFFFFF] = PASS
Background[0xffFF0000] = PASS
Background[0xff00FF00] = PASS
Background[0xff0000FF] = PASS
Background[0xff00FFFF] = PASS
Background[0xffFFFF00] = PASS
Background[0xffFF00FF] = PASS
Duration = 28.3567230701 s
Total_Result = PASS
[Videox_Rotate_008]
type = testcase
summary = rotation
Rotation[0] = PASS
Rotation[1] = PASS
Rotation[2] = PASS
Rotation[3] = PASS
Duration = 14.0116529465 s
Total_Result = PASS
Thank you!
Short and simple gnu awk:
awk -F= -v RS='' '{print $1 $NF}' file
[Linux_MP3Enc_xffv.2_Con_37_003] PASS
[Composer__vtx_007] PASS
[Videox_Rotate_008] PASS
If you do not like the brackets:
awk -F'[]=[]' -v RS='' '{print $2 $NF}' file
Linux_MP3Enc_xffv.2_Con_37_003 PASS
Composer__vtx_007 PASS
Videox_Rotate_008 PASS
Using sed as tagged (although other tools would probably be more natural to use) :
sed -nE '/^\[.*\]$/h;s/^Results= ?//;t r;b;:r;H;x;s/\n/ /;p'
Explanation :
/^\[.*\]$/h # matches the [...] lines, put them in the hold buffer
s/^Results= ?// # matches the Results= lines, discards the useless part
t r;b # on lines which matched, jump to label r;
# otherwise jump to the end (and start processing the next line)
:r;H;x;s/\n/ /;p # label r; append the pattern space (which contains the end of the Results= line)
# to the hold buffer. Switch Hold buffer and pattern space,
# replace the linefeed in the pattern space by a space and print it
You can try it here.
One way to solve this is using a regular expression such as:
(?<testId>test\d+)(?:.*\n){4}.*(?<outcome>PASS|FAIL)
The regex matches your sample output and stores the test id (e.g. "test1") in the capture group named "testId" and the outcome (e.g. "PASS") in the capture group "outcome".
(Test it in regexr)
The regex can be used in any language with regex support. The below code shows how to do it in Python.
(Test it in repl.it)
import re
# Read from input.txt
with open('input.txt', 'r') as f:
indata = f.read()
# Modify the regex slightly to fit Python regex syntax
pattern = '(?:.*)(?P<testId>test\d+)(?:.*\n){4}.*(?P<outcome>PASS|FAIL)'
# Get a generator which yeilds all matches
matches = re.finditer(pattern, indata)
# Combine the matches to a list of strings
outputs = ['{} {}'.format(m.group('testId'), m.group('outcome')) for m in matches]
# Join all rows to one string
output = '\n'.join(outputs)
# Write to output.txt
with open('output.txt', 'w') as f:
f.write(output)
Running the above script on input.txt containing:
[test1]
duration
summary
code=
Results= PASS
[test2]
duration
summary=x
code=
Results=FAIL
[test444]
duration
summary=x
code=
Results= PASS
yields a file output.txt containing:
test1 PASS
test2 FAIL
test444 PASS
In order to print the first and last line from the block, how about:
awk -v RS="" '{
n = split($0, a, /\n/)
print a[1]
print a[n]
}' input.txt
Result for the 1st example:
[Linux_MP3Enc_xffv.2_Con_37_003]
Total_Result = PASS
[Composer__vtx_007]
Total_Result = PASS
[Videox_Rotate_008]
Total_Result = PASS
The man page of awk tells:
If RS is set to the null string, then records are separated by blank lines.
You can easily split the block with blank lines with this feature.
Hope this helps.

Sed: How to insert a pattern which includes single ticks?

I'm trying to use sed to replace a specific line within a configuration file:
The pattern for the line I want to replace is:
ALLOWED_HOSTS.*
The text I want to insert is:
'$PublicIP' (Including the single ticks)
But when I run the command:
sed 's/ALLOWED_HOSTS.*/ALLOWED_HOSTS = ['$PublicIP']/g' /root/project/django/mysite/mysite/settings.py
The line is changed to:
ALLOWED_HOSTS = [1.1.1.1]
instead of:
ALLOWED_HOSTS = ['1.1.1.1']
How shall I edit the command to include the single ticks as well?
You could try to escape the single ticks , or better you can reassign the variable including the simple ticks:
PublicIP="'$PublicIP'".
By the way even this sed without redifining var, works ok in my case:
$ a="3.3.3.3"
$ echo "ALLOWED_HOSTS = [2.2.2.2]" |sed 's/2.2.2.2/'"'$a'"'/g'
ALLOWED_HOSTS = ['3.3.3.3']
Even this works ok:
$ echo "ALLOWED_HOSTS = [2.2.2.2]" |sed "s/2.2.2.2/'$a'/g"
ALLOWED_HOSTS = ['3.3.3.3']

Use variable with quotes with system in MATLAB

I have
myVar.value = 123521#machine OK
now I'm using this variable with system command as it's an argument passed to a binary .exe
so I have to add quotes to myVar.value as it caontains spaces
I tried :
'''myVar.value''' but this will give 'myVar.value', whereas I just want to have the result equal to "123521#machine OK"
how could I use the quotes in this case ?
Try this:
x = ['"' myVar.value '"']
I think you can use double quote characters within strings demarcated by single quotes. Within a string demarcated by single quotes characters by doubling up:
x = ['''' myVar.value '''']

Why is my command line argument being interpreted as a Boolean (Perl 6)?

Given this program:
#!/bin/env perl6
sub MAIN ($filename='test.fq', :$seed=floor(now) )
{
say "Seed is $seed";
}
When I run it without any command line arguments, it works fine. However, when I give it a command line argument for seed, it says that its value is True:
./seed.p6 --seed 1234
Seed is True
Why is the number 1234 being interpreted as a boolean?
Perl 6's MAIN argument handling plays well with gradual typing. Arguments can, and should be typecast to reduce ambiguity and improve validation:
#!/bin/env perl6
sub MAIN (Str $filename='test.fq', Int :$seed=floor(now))
{
say "Seed is $seed.";
}
After typecasting seed to Int, this option must be given a numeric argument and no longer defaults to a Boolean:
perl6 ./seed.pl -seed 1234
Usage:
./seed.pl [--seed=<Int>] [<filename>]
perl6 ./seed.pl -seed=abc
Usage:
./seed.pl [--seed=<Int>] [<filename>]
perl6 ./seed.pl -seed=1234
Seed is 1234.
You need to use an = sign between your option --seed and its value 1234:
./seed.p6 --seed=1234
Since you have a positional argument in your MAIN subroutine signature (i.e. $filename), the first argument not tied to an value with an = sign will be assigned to it.
Your original
./seed.p6 --seed 1234
was being interpreted as if 1234 were the filename (i.e. it was assigned to the variable $filename). Since a command line option without an argument is considered to be True, $seed was being assigned True in your original invocation of that script.