I'm trying to write a grub2 bootloader script but if statements always evaluate to true:
if [ -s blabla ] ; then set zzz0="1" ; fi
if [ ! -s blabla ] ; then set zzz1="1" ; fi
set TEST_VAR=foo
if [ "x${TEST_VAR}" = "xfoo" ] ; then set zzz2="1" ; fi
if [ "x${TEST_VAR}" = "xbar" ] ; then set zzz3="1" ; fi
if [ $TEST_VAR = foo ] ; then set zzz4="1" ; fi
if [ $TEST_VAR = bar ] ; then set zzz5="1" ; fi
So, after running this script, I see all zzz (zzz0, zzz1, zzz2, zzz3, zzz4, zzz5)variables set to 1. What am I doing wrong?
Thanks,
Johnny
if [ ! "${myvar}" = "" ]; then
(lines here)
else
(lines here)
fi
if [ "${myvar}" = "fred" ]; then
(lines here)
else
(lines here)
fi
Related
I am trying to convert a regex based solution for the knapsack problem from Perl to raku. Details on Perlmonks
The Perl solution creates this regex:
(?<P>(?:vvvvvvvvvv)?)
(?<B>(?:vv)?)
(?<Y>(?:vvvv)?)
(?<G>(?:vv)?)
(?<R>(?:v)?)
0
(?=
(?(?{ $1 })wwww|)
(?(?{ $2 })w|)
(?(?{ $3 })wwwwwwwwwwww|)
(?(?{ $4 })ww|)
(?(?{ $5 })w|)
)
which gets matched against vvvvvvvvvvvvvvvvvvv0wwwwwwwwwwwwwww. After that the match hash %+ contains the items to put in the sack.
My raku conversion is:
$<B> = [ [ vv ]? ]
$<P> = [ [ vvvvvvvvvv ]? ]
$<R> = [ [ v ]? ]
$<Y> = [ [ vvvv ]? ]
$<G> = [ [ vv ]? ]
0
<?before
[ { say "B"; say $/<B>; say $0; say $1; $1 } w || { "" } ]
[ { say "P"; say $/<P>; say $0; say $1; $2 } wwww || { "" } ]
[ { say "R"; say $/<R>; say $0; say $1; $3 } w || { "" } ]
[ { say "Y"; say $/<Y>; say $0; say $1; $4 } wwwwwwwwwwww || { "" } ]
[ { say "G"; say $/<G>; say $0; say $1; $5 } ww || { "" } ]
which also matches vvvvvvvvvvvvvvvvvvv0wwwwwwwwwwwwwww. But the match object, $/ does not contain anything useful. Also, my debug says all say Nil, so at that point the backreference does not seem to work?
Here's my test script:
my $max-weight = 15;
my %items =
'R' => { w => 1, v => 1 },
'B' => { w => 1, v => 2 },
'G' => { w => 2, v => 2 },
'Y' => { w => 12, v => 4 },
'P' => { w => 4, v => 10 }
;
my $str = 'v' x %items.map(*.value<v>).sum ~
'0' ~
'w' x $max-weight;
say $str;
my $i = 0;
my $left = my $right = '';
for %items.keys -> $item-name
{
my $v = 'v' x %items{ $item-name }<v>;
my $w = 'w' x %items{ $item-name }<w>;
$left ~= sprintf( '$<%s> = [ [ %s ]? ] ' ~"\n", $item-name, $v );
$right ~= sprintf( '[ { say "%s"; say $/<%s>; say $0; say $1; $%d } %s || { "" } ]' ~ "\n", $item-name, $item-name, ++$i, $w );
}
use MONKEY-SEE-NO-EVAL;
my $re = sprintf( '%s0' ~ "\n" ~ '<?before ' ~ "\n" ~ '%s>' ~ "\n", $left, $right );
say $re;
dd $/ if $str ~~ m:g/<$re>/;
This answer only covers what's going wrong. It does not address a solution. I have not filed corresponding bugs. I have not yet even searched bug queues to see if I can find reports corresponding to either or both the two issues I've surfaced.
my $lex-var;
sub debug { .say for ++$, :$<rex-var>, :$lex-var }
my $regex = / $<rex-var> = (.) { $lex-var = $<rex-var> } <?before . { debug }> / ;
'xx' ~~ $regex; say $/;
'xx' ~~ / $regex /; say $/;
displays:
1
rex-var => Nil
lex-var => 「x」
「x」
rex-var => 「x」
2
rex-var => Nil
lex-var => 「x」
「x」
Focusing first on the first call of debug (the lines starting with 1 and ending at rex-var => 「x」), we can see that:
Something's gone awry during the call to debug: $<rex-var> is reported as having the value Nil.
When the regex match is complete and we return to the mainline, the say $/ reports a full and correctly populated result that includes the rex-var named match.
To begin to get a sense of what's gone wrong, please consider reading the bulk of my answer to another SO question. You can safely skip the Using ~. Footnotes 1,2, and 6 are also probably completely irrelevant to your scenario.
For the second match, we see that not only is $<rex-var> reported as being Nil during the debug call, the final match variable, as reported back in the mainline with the second say $/, is also missing the rex-var match. And the only difference is that the regex $regex is called from within an outer regex.
I am trying loop control. while loop then a for loop and inside it there are couple of if loops, if 3 of the if loop satisfies it should exit the for loop to continue with while loop else it should exit the if loop to continue rest of for loop iterations
LIMIT=100
while [ "count" -le "$LIMIT" ]
do
for i in 1 2 3 4 5
do
var a
var b
var c
var d
if [ $d -eq 1 ] && [ $a == Done ] && [ $b -eq 0 ]
then
echo "$c" | tr '\n' '\t'
echo "Successful"
break 2 # Need to exit entire for loop
elif [ $d -eq 0 ] && [ $a == Done ] && [ $b -eq 0 ]
then
break # Need to go to next iteration of for
elif [ $a == Active ]
then
echo "Active" # Need to exit entire for loop
break 2
elif [ $d -eq 1 ] && [ $a == Done ] && [ $b -gt 0 ]
then
echo "Fail" # Need to exit entire for loop
break 2
elif [ $a == Queued ]
then
echo "Queued" # Need to exit entire for loop
break 2
else
echo "Nothing"
fi
done
done
For some reason it exits everything when first if loop is true.
Got it, actually I was using break 2 which was exiting for as well as while as if is already being exited so using single break would let me exit for loop entirely, and to continue for next iteration for any of the if loop needed to use continue.
so the code should be
LIMIT=100
while [ "count" -le "$LIMIT" ]
do
for i in 1 2 3 4 5
do
var a
var b
var c
var d
if [ $d -eq 1 ] && [ $a == Done ] && [ $b -eq 0 ]
then
echo "$c" | tr '\n' '\t'
echo "Successful"
break # will exit entire for loop
elif [ $d -eq 0 ] && [ $a == Done ] && [ $b -eq 0 ]
then
continue # will go to next iteration of for
elif [ $a == Active ]
then
echo "Active"
break # will exit entire for loop
elif [ $d -eq 1 ] && [ $a == Done ] && [ $b -gt 0 ]
then
echo "Fail"
break # will exit entire for loop
elif [ $a == Queued ]
then
echo "Queued"
break # will exit entire for loop
else
echo "Nothing"
fi
done
done
Need to have a read statement in BASH that will ask user to input 2 digits on the same line with a space in between. Check if both are digits and there is a space in between.
#!/bin/bash
while :
do
read -p "digits a b?: " resp
if [ -z "${resp}" ] ; then continue;fi
respCtrl=`echo $resp | sed 's/[^0-9 ]//g'`
if [ ! ${#respCtrl} -eq ${#resp} ] ; then continue ;fi
set ${resp}
digit1=$1
digit2=$2
if [ "${digit1} ${digit2}" != "${resp}" ] ; then continue;fi
echo ${digit1} ${digit2}
break
done
#!/bin/bash
result=""
while [[ $result == *" "* || $result == "" ]];do
read -p "Type 2 digits without space:" result;
echo "Error";
done
I'm trying to make a program that reads in n strings and checks them for pertaining to a regex pattern: XXXXX1234X where X is an uppercase character and {1,2,3,4} is any digit. As far as I checked, the regex pattern is correct. The problem seems to be in the input and comparison of strings.
read n
i=0
declare -a str
while [ $i -lt $n ]
do
read 'str[$i]'
i=$((i+1))
done
i=0
while [ $i -lt $n ]
do
[[ $(str[$i]) =~ ^([A-Z]){5}([0-9]){4}([A-Z]){1}$ ]] && echo YES || echo NO
i=$((i+1))
done
I did a minor modification to your code, I replaced the ( and ) with { } in the regex test:
[[ ${str[$i]} =~ ^...
Ran some test and it worked:
#!/bin/bash
read n
i=0
declare -a str
while [ $i -lt $n ]
do
read 'str[$i]'
i=$((i+1))
done
i=0
while [ $i -lt $n ]
do
[[ ${str[$i]} =~ ^([A-Z]){5}([0-9]){4}([A-Z]){1}$ ]] && echo YES || echo NO
i=$((i+1))
done
I am struggling to put together a regex to match a function call like following:
funcname (...(..
...)..(..(...
)...)..)
so the function can have multiple bracketed parameters spread over multiple lines.
The dots can be anything else appart from '(' or ')'.
I would use the regex with sed or grep.
Thanks,
Risto
So, I went on writing this simple parser in bash. It is not perfect but can serve as a starting point. For example it cannot distinguish if a function call is commented out or not, etc.
while read file; do
linenum=0
while IFS= read -r line; do
(( linenum++ ))
if [ $fmatch -eq 0 ]; then
if [[ ! $line =~ $funcname ]]; then
continue
fi
linenummatch=$linenum
fmatch=1
fstripped=0
openbracket=0
closebracket=0
spacenum=0
fi
linelen=${#line}
position=0
while [ $position -lt $linelen ]; do
if [ $fstripped -eq 0 ]; then
subline=${line:$position}
mlen=`expr "$subline" : "$funcname"`
if [ $mlen -gt 0 ]; then
(( position+=mlen ))
resultstr=$funcname
fstripped=1
continue
fi
(( position++ ))
continue
fi
ch=${line:$position:1}
case $ch in
'(' )
(( openbracket++ ))
spacenum=0
newresultstr="$resultstr$ch"
;;
')' )
if [ $openbracket -eq 0 ]; then
fmatch=0
break
fi
(( closebracket++ ))
spacenum=0
newresultstr="$resultstr$ch"
if [ $closebracket -eq $openbracket ]; then
echo "$file $linenummatch $newresultstr"
fmatch=0
break
fi
;;
' ' | '\t' )
if [ $spacenum -eq 0 ]; then
newresultstr=$resultstr' '
fi
(( spacenum++ ))
;;
'\n' )
# line feeds are skipped
;;
* )
if [ $openbracket -eq 0 ]; then
fmatch=0
break
fi
spacenum=0
newresultstr="$resultstr$ch"
;;
esac
resultstr=$newresultstr
(( position++ ))
done
done < $file
done < $filelist
As C is an irregular language you may need a parser for that. The problem you will have is working out when all the open brackets are closed again. You can do some fairly strange things with C. For example you can have a parameter that is a function definition in its own right. For example consider in the following program how you would distinguish between a(), b(), c(), d(), e(), f() and g()?
#include <stdio.h>
#define f(c) c;
char a()
{
return f('z');
}
/*
A function in a comment.
char b()
{
return 'y';
}
*/
char c(char d())
{
return d();
}
#if 0
This code is not included
char g()
{
return 'v';
}
#endif
void main()
{
printf ("A function in a string: char e() { return 'x'; }\n");
printf ("The result from passing a to c: %c\n", c(a));
printf ("Press enter to exit");
getchar();
}
I have seen many attempts to do this kind of thing with Regular Expressions but most of them end up with Catastrophic Backtracking issues.