this is my first post, so be gentle please!
So, I have input files (.in) for an in-house program. The syntax is as follows (for example):
$set (code) $end
$run
(code)
$end
$cmt this is a comment
$cmt this is
a block comment
$end
My situation is I want all the $set and $run to be red with their corresponding $end to be red also. Everything in between has to be nominal color (grey).
I simply use the
syntax match inCMD "\$SET"
for that and it works fine.
Where I have a problem is that I want the "$CMT" to be yellow so i use
syntax match inCMT "/^\$CMT.*$"
The particularity is that $CMT does not have to have a corresponding $END. So, if there is no $END (or that it figures at the end of the same line as $CMT, i want the line to be yellow, and the line after to be outside the syntax region. However, if i want to do a block comment and that there is a corresponding $END to this $CMT, everything inside has to be yellow.
I came up with
syntax commands
but i have a problem on line 14-17 of the 2nd picture:
syntax example.
If a $set is directly under the $cmt, the text inside the $set will be yellow instead of simply white.
The other problem is that the $end corresponding to $set are white and not red.
How can i solve this?
Thanks a lot!
edit: Syntax file:
syntax case ignore
syntax match inCMT /^\$CMT.*$/
syntax match inCMD "\$SET"
syntax match inCMD "\$RUN"
sy region inCMT matchgroup=inCMT start= /^\$CMT.*$/ end=/\(^\$end\)\|\(^\s*$\)/ contains=inCMD
:sy region inCMD matchgroup=inCMD start= /\v($(SET))/ end=/\(^\$end\)\|\(^\s*$\)/ contained
:hi inCMT ctermfg=yellow
:hi inCMD ctermfg=red
Input file:
$cmt eoipwejf
iowejwed
$end
$set
weoifjwef
$end
$set
$end
$cmt
$set ewdiw
efef
$end
$set
effef
$end
$cmt
efoiwef
$end
$cmt
wd
$END
wd
$set
deiuwf = ewoiw
ewofoi we
$end
$cmt fefef
$cmt
efwef
$end
$set
$set
$set
$cmt ewfoief
wdwwd
$end
$set efopwef
fwfewf
eiojf
$end
$set
ere
wd
$cmt
$end
effe
$cmt
wdeoiqwd
$end
edfeef
$run
goto
$cmt
wdqwd
$end
2nd edit: What i want as final result (colors in brackets)
(y) yellow
(r) red
(n) nominal
Block comment:
$cmt foo (y)
bar (y)
$end (y)
$cmt (y)
foo (y)
bar (y)
$end (y)
$cmt (y)
foo (y)
bar(y)
$end (y)
Line comment:
$cmt (y)
$set (r) foo = bar (n) $end (r)
$cmt foo bar (y)
$set (r)
foo = bar (n)
$end (r)
I think these are all the cases.
This worked for me:
syntax clear
syntax case ignore
syntax match inCMD "\$set"
syntax match inCMD "\$cmd"
syntax match inCMD "\$end"
syntax region inCMT start=/^\$cmt/ end=/\$end\|\$\#=/
hi inCMT ctermfg=yellow
hi inCMD ctermfg=red
It seems to match your update indicating which color each line or word should take. Normally only the keywords ($cmd, $run and $end) are red, but for a comment the whole block is yellow, including the final $end.
The trick to match a comment with or without an $end was to do a zero-width match on a single $ (that's the \$\#= part of the regex.) Since regular expressions return the longest match first, whenever $end is found it will be matched (and highlighted yellow), but if a $ is otherwise matched, it ends the region but it doesn't become part of it, so it won't be highlighted yellow (and it turns out it's still available to be highlighted red if it's one of the other matching commands, which was important in this case.)
I noticed you had an $end further down one line, so I didn't anchor the commands anywhere. My first instinct was to use ^ to have them at the start of the line and also use a $ to only allow $end to be by itself on a line. But I removed all that and it turns out it still works as expected. Feel free to add those back if you think they make sense.
Related
https://www.vimgolf.com/challenges/9v006233d72d000000000219
Start file
#!/bin/bash
a = 5
b = 10
sum = $a + $b
echo $sum
mul = $a * $b
echo $mul
End file
#!/bin/bash
a=5
b=10
sum=$((a + b))
echo $sum
mul=$((a * b))
echo $mul
=================================
The keystroke in this problem was 26 but I only get 41.
The way I used it
:%s/ = /=/g
:%s/$a/$((a/g
:%s/$b/b))/g
I don't know how to reduce keystrokes more. Please give me some advice.
/g means "do the substitution on every match in the line". There is only one match for each pattern so the /gs are not necessary:
:%s/ = /=<CR>
:%s/$a/$((a<CR>
:%s/$b/b))<CR>
You are down to 36 keystrokes.
See :help :s_g.
In this specific case, $a + $b can be matched with a single pattern, $.*b, so you could fuse the two last substitutions into a single one:
:%s/ = /=<CR>
:%s/$.*b/$((&))<CR>
And you are down to 26 keystrokes.
See :help s/\&.
I'm using .conf which contain keys and values.
Some keys contains numbers like
deployment.conf
EAR_COUNT=2
EAR_1=xxx.ear
EAR_2=yyy.ear
When I try to retrieve that value using particular key and compare with integer value i.e. natural number.
But Whatever I retrieved values from .conf ,it is should be String datatype.
How should I compare both value in Linux Bash script.
Simply : How should I compare two values in Linux.?
Ex :
. ./deployment.conf
count=$EAR_COUNT;
echo "count : $count";
if [ $count -gt 0 ]; then
echo "Test"
fi
I'm getting following error :
count : 2
: integer expression expected30: [: 2
They're all strings in bash, notwithstanding your ability to do typeset-type things to flag them differently.
If you want to do numeric comparisons, just use -eq (or its brethren like -gt, -le) rather than ==, != and so on:
if [[ $num -eq 42 ]] ; then
echo Found the answer
fi
The full range of comparison operators can be found in the bash manpage, under CONDITIONAL EXPRESSIONS.
If you have something that you think should be a number and it's not working, I'll warrant it's not a number. Do something like:
echo "[$count]"
to make sure it doesn't have a newline at the end or, better yet, get a hex dump of it in case it holds strange characters, like Windows line endings:
echo -n $count | od -xcb
The fact that you're seeing:
: integer expression expected30: [: 2
with the : back at the start of the line, rather than the more usual:
-bash: [: XX: integer expression expected
tends to indicate the presence of a carriage return in there, which might be from deployment.conf having those Windows line endings (\r\n rather than the UNIXy \n).
The hex dump should make that obvious, at which point you need to go and clean up your configuration file.
Ref : http://linux.die.net/man/1/bash
-eq, -ne, -lt, -le, -gt, or -ge
These are arithmetic binary operators in bash scripting.
I have checked your code,
deployment.conf
# CONF FILE
EAR_COUNT=5
testArithmetic.sh
#!/bin/bash
. ./deployment.conf
count=$EAR_COUNT;
echo "count : $count";
if [ $count -gt 0 ]; then
echo "Test"
fi
running the above script evaluates to numeric comparison for fine. Share us your conf file contents, if you are facing any issues. If you are including the conf file in your script file, note the conf file must have valid BASH assignments, which means, there should be no space before and after '=' sign.
Also, you have mentioned WAR_COUNT=3 in conf part and used 'count=$EAR_COUNT;' in script part. Please check this too.
Most likely you have some non-integer character like \r in your EAR_COUNT variable. Strip all non-digits while assigning to count like this:
count=${EAR_COUNT//[^[:digit:]]/}
echo "count : $count";
if [[ $count -gt 0 ]]; then
echo "Test"
fi
Whatever you want to call it, I'm trying to figure out a way to take the contents of an existing string and evaluate them as a double-quoted string. For example, if I create the following strings:
$string = 'The $animal says "meow"'
$animal = 'cat'
Then, Write-Host $string would produce The $animal says "meow". How can I have $string re-evaluated, to output (or assign to a new variable) The cat says "meow"?
How annoying...the limitations on comments makes it very difficult (if it's even possible) to include code with backticks. Here's an unmangled version of the last two comments I made in response to zdan below:
----------
Actually, after thinking about it, I realized that it's not reasonable to expect The $animal says "meow" to be interpolated without escaping the double quotes, because if it were a double-quoted string to begin with, the evaluation would break if the double quotes weren't escaped. So I suppose the answer would be that it's a two step process:
$newstring = $string -replace '"', '`"'
iex "`"$string`""
One final comment for posterity: I experimented with ways of getting that all on one line, and almost anything that you'd think works breaks once you feed it to iex, but this one works:
iex ('"' + ($string -replace '"', '`"') + '"')
Probably the simplest way is
$ExecutionContext.InvokeCommand.ExpandString($var)
You could use Invoke-Expression to have your string reparsed - something like this:
$string = 'The $animal says `"meow`"'
$animal = 'cat'
Invoke-Expression "Write-Host `"$string`""
Note how you have to escape the double quotes (using a backtick) inside your string to avoid confusing the parser. This includes any double quotes in the original string.
Also note that the first command should be a command, if you need to use the resulting string, just pipe the output using write-output and assign that to a variable you can use later:
$result = Invoke-Expression "write-output `"$string`""
As noted in your comments, if you can't modify the creation of the string to escape the double quotes, you will have to do this yourself. You can also wrap this in a function to make it look a little clearer:
function Invoke-String($str) {
$escapedString = $str -replace '"', '`"'
Invoke-Expression "Write-Output `"$escapedString`""
}
So now it would look like this:
# ~> $string = 'The $animal says "meow"'
# ~> $animal = 'cat'
# ~> Invoke-String $string
The cat says "meow"
You can use the -f operator. This is the same as calling [String]::Format as far as I can determine.
PS C:\> $string = 'The {0} says "meow"'
PS C:\> $animal = 'cat'
PS C:\> Write-Host ($string -f $animal)
The cat says "meow"
This avoids the pitfalls associated with quote stripping (faced by ExpandString and Invoke-Expression) and arbitrary code execution (faced by Invoke-Expression).
I've tested that it is supported in version 2 and up; I am not completely certain it's present in PowerShell 1.
Edit: It turns out that string interpolation behavior is different depending on the version of PowerShell. I wrote a better version of the xs (Expand-String) cmdlet with unit tests to deal with that behavior over here on GitHub.
This solution is inspired by this answer about shortening calls to object methods while retaining context. You can put the following function in a utility module somewhere, and it still works when you call it from another module:
function xs
{
[CmdletBinding()]
param
(
# The string containing variables that will be expanded.
[parameter(ValueFromPipeline=$true,
Position=0,
Mandatory=$true)]
[string]
$String
)
process
{
$escapedString = $String -replace '"','`"'
$code = "`$ExecutionContext.InvokeCommand.ExpandString(`"$escapedString`")"
[scriptblock]::create($code)
}
}
Then when you need to do delayed variable expansion, you use it like this:
$MyString = 'The $animal says $sound.'
...
$animal = 'fox'
...
$sound = 'simper'
&($MyString | xs)
&(xs $MyString)
PS> The fox says simper.
PS> The fox says simper.
$animal and $sound aren't expanded until the last two lines. This allows you to set up a $MyString up front and delay expansion until the variables have the values you want.
Invoke-Expression "`"$string`""
In my perl script I want to have both versions of $config directory:
my $config='$home/client/config';
and
my $config_resolved="$home/client/config";
But I want to get $config_resolved from $config, i.e. something like this:
my $config_resolved=resolve_vars($config);
How can I do such thing in perl?
From the Perl FAQ (which every Perl programmer should read at least once):
How can I expand variables in text strings?
(contributed by brian d foy)
If you can avoid it, don't, or if you can
use a templating system, such as Text::Template or Template Toolkit,
do that instead. You might even be able to get the job done with
sprintf or printf:
my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
However, for the one-off simple case where I don't want to pull out a
full templating system, I'll use a string that has two Perl scalar
variables in it. In this example, I want to expand $foo and $bar to
their variable's values:
my $foo = 'Fred';
my $bar = 'Barney';
$string = 'Say hello to $foo and $bar';
One way I can do this involves the substitution operator and a double /e flag. The
first /e evaluates $1 on the replacement side and turns it into $foo. The
second /e starts with $foo and replaces it with its value. $foo,
then, turns into 'Fred', and that's finally what's left in the string:
$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
The /e will also silently ignore violations of strict, replacing undefined
variable names with the empty string. Since I'm using the /e flag
(twice even!), I have all of the same security problems I have with
eval in its string form. If there's something odd in $foo, perhaps
something like #{[ system "rm -rf /" ]}, then I could get myself in
trouble.
To get around the security problem, I could also pull the
values from a hash instead of evaluating variable names. Using a
single /e, I can check the hash to ensure the value exists, and if it
doesn't, I can replace the missing value with a marker, in this case
??? to signal that I missed something:
my $string = 'This has $foo and $bar';
my %Replacements = (
foo => 'Fred',
);
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
exists $Replacements{$1} ? $Replacements{$1} : '???'
/eg;
print $string;
I use eval for this.
So, you must replace all scalars (their names) with their values.
$config = 'stringone';
$boo = '$config/any/string';
$boo =~ s/(\$\w+)/eval($1)/eg;
print $boo;
Because you are using my to declare it as private variable, you might as well use a /ee modifier. This can find variables declared to be in local scope:
$boo =~ s/(\$\w+)/$1/eeg;
This is most tidily and safely done by the double-eval modifier on s///.
In the program below, the first /e evaluates the string $1 to get $home, while the second evaluates $home to get the variable's value HOME.
use strict;
my $home = 'HOME';
my $config = '$home/client/config';
my $config_resolved = resolve_vars($config);
print $config_resolved, "\n";
sub resolve_vars {
(my $str = shift) =~ s/(\$\w+)/$1/eeg;
return $str;
}
output
HOME/client/config
The following code gives
[: -ge: unary operator expected
when
i=0
if [ $i -ge 2 ]
then
#some code
fi
why?
Your problem arises from the fact that $i has a blank value when your statement fails. Always quote your variables when performing comparisons if there is the slightest chance that one of them may be empty, e.g.:
if [ "$i" -ge 2 ] ; then
...
fi
This is because of how the shell treats variables. Assume the original example,
if [ $i -ge 2 ] ; then ...
The first thing that the shell does when executing that particular line of code is substitute the value of $i, just like your favorite editor's search & replace function would. So assume that $i is empty or, even more illustrative, assume that $i is a bunch of spaces! The shell will replace $i as follows:
if [ -ge 2 ] ; then ...
Now that variable substitutions are done, the shell proceeds with the comparison and.... fails because it cannot see anything intelligible to the left of -gt. However, quoting $i:
if [ "$i" -ge 2 ] ; then ...
becomes:
if [ " " -ge 2 ] ; then ...
The shell now sees the double-quotes, and knows that you are actually comparing four blanks to 2 and will skip the if.
You also have the option of specifying a default value for $i if $i is blank, as follows:
if [ "${i:-0}" -ge 2 ] ; then ...
This will substitute the value 0 instead of $i is $i is undefined. I still maintain the quotes because, again, if $i is a bunch of blanks then it does not count as undefined, it will not be replaced with 0, and you will run into the problem once again.
Please read this when you have the time. The shell is treated like a black box by many, but it operates with very few and very simple rules - once you are aware of what those rules are (one of them being how variables work in the shell, as explained above) the shell will have no more secrets for you.
Judging from the error message the value of i was the empty string when you executed it, not 0.
I need to add my 5 cents. I see everybody use [ or [[, but it worth to mention that they are not part of if syntax.
For arithmetic comparisons, use ((...)) instead.
((...)) is an arithmetic command, which returns an exit status of 0 if
the expression is nonzero, or 1 if the expression is zero. Also used
as a synonym for "let", if side effects (assignments) are needed.
See: ArithmeticExpression
Your piece of script works just great. Are you sure you are not assigning anything else before the if to "i"?
A common mistake is also not to leave a space after and before the square brackets.