What does =~ mean in VimScript? - operators

I can't for the life of me find an answer to this either on google or here or in the help files.
if "test.c" =~ "\.c"
At first I thought =~ mean ends in, but observe these results:
Command Result
echo "test.c" =~ "\.c" 1
echo "test.c" =~ "\.pc" 0
echo "test.pc" =~ "\.c" 1
echo "testc" =~ "\.c" 1
echo "ctest" =~ "\.c" 1
echo "ctestp" =~ "\.pc" 0
echo "pctestp" =~ "\.pc" 0
echo ".pctestp" =~ "\.pc" 0
An explanation would be great. A link to a site attempting to decipher VimScript would be even better.

From the Vim documentation, it does a pattern match of the right operand (as a pattern) inside the left.
For strings there are two more items:
a =~ b matches with
a !~ b does not match with
The left item "a" is used as a string. The right item "b" is used as a pattern, like what's used for searching. Example:
:if str =~ " "
: echo "str contains a space"
:endif
:if str !~ '\.$'
: echo "str does not end in a full stop"
:endif
You might try your test cases again. I get, for example, inconsistent with yours:
echo ".pctestp" =~ "\.pc" 1
And double-quotes vs single quotes seem to affect how the backslash is interpreted:
echo "test.pc" =~ "\.c" 1
echo "test.pc" =~ '\.c' 0

From the docs:
http://vimdoc.sourceforge.net/htmldoc/usr_41.html
For strings there are two more items:
a =~ b matches with
a !~ b does not match with
The left item "a" is used as a string. The right item "b" is used as a
pattern, like what's used for searching. Example:
:if str =~ " "
: echo "str contains a space"
:endif
:if str !~ '\.$'
: echo "str does not end in a full stop"
:endif

Related

sed or awk with variable and special charachters

I want to use awk or sed to substitute 1 line in my file:
my file content is:
server.modules += ( "mod_redirect" )
$SERVER["socket"] == ":8080" {
$HTTP["host"] =~ "(.*)" {
url.redirect = ( "^/(.*)" => "https://someurl.com/unauthorised" )
}
}
I want to change the line containing url.redirect
The new line is in variable and containing some special charachter will be somthing like this url.redirect = ( "^/(.*)" => "http://newurl.com/newpath" )
so I used the following sed comand:
sed "/url\.redirect =/s/.*/$newline/" 10-redirect.conf
But I got error related to the special characters inside the newline variable.
the newline is an argument of my shell function so I can not change it and add some skip characters inside.
How to use variables with special charachters in sed or awk?
With GNU sed and c command (which replaces the matched lines with the string provided). If there are spaces at the start of string, prefix \ to preserve them
sed '/url\.redirect =/c\'"$newline"
However, c command will still allow escape sequences, for example:
$ s=' rat\tdog\nwolf'
$ seq 3 | sed '2c\'"$s"
1
rat dog
wolf
3
To add contents literally and robustly, use r command
echo "$newline" | sed -e '/url\.redirect =/ {r /dev/stdin' -e 'd}'
Here's r command in action
$ s=' rat\tdog\nwolf'
$ echo "$s" | sed -e '2 {r /dev/stdin' -e 'd}' <(seq 3)
1
rat\tdog\nwolf
3
Could you please try following. This should put same spaces in front of new value what were present before.
newline='url.redirect = ( "^/(.*)" => "https://example.com/authorised" )'
awk -v line="$newline" '
/url.redirect =/{
match($0,/^ +/)
print substr($0,RSTART,RLENGTH) line
next
}
1
' Input_file
You are getting error in sed because it is using a regex and your replacement string may contain meta-characters such as & or / (delimiters) etc.
This awk would be safer to use due to non-regex approach:
newline='url.redirect = ( "^/(.*)" => "https://example.com/authorised" )'
awk -i inplace -v line="$newline" 'index($0, "url.redirect =") {
sub(/[^[:blank:]].*/, "")
$0 = $0 line
} 1' file
server.modules += ( "mod_redirect" )
$SERVER["socket"] == ":8080" {
$HTTP["host"] =~ "(.*)" {
url.redirect = ( "^/(.*)" => "https://example.com/authorised" )
}
}
Note that using ENVIRON would allow all the shell special characters to
awk:
export newline
awk -i inplace 'index($0, "url.redirect =") {
sub(/[^[:blank:]].*/, "")
$0 = $0 ENVIRON["newline"]
} 1' file

String comparison in ksh never succeeding

I have the next script, and when trying to compare variable value if equals "NO" or "SI" (yes in spanish) it's not working for some reason I keep going all the time through the else (SI) although the real value in the variable is "NO". It's even being printed in the email subject.
I fear I could be some extra invisible character I can't see but it's there?
Here is the script:
#!/usr/bin/ksh
VAR=$(/home/userName/scripts/loadedresource.ksh | egrep 'SI|NO')
MAIL_FILE="testfile.txt"
rm -f $MAIL_FILE
echo "From:Script" > $MAIL_FILE
echo "To:Me<me#company.com>" >> $MAIL_FILE
echo "Subject:RESOURCE LOADED-> $VAR" >> $MAIL_FILE
echo "Content-Type: text/html" >> $MAIL_FILE
echo "<html>" >> $MAIL_FILE
echo "<body style='font-family:calibri;font-size:14px;'>" >> $MAIL_FILE
if [ "$VAR" == "NO" ]
then
echo "<h2> Resource not loaded, please open ticket </h2>" >> $MAIL_FILE
else
echo "<h2> Resource loaded successfully </h2>" >> $MAIL_FILE
fi
mail me#company.com < $MAIL_FILE
== is not a valid comparison operator in POSIX test. If your particular implementation of ksh doesn't implement an extension adding it, you may need to use
if [ "$VAR" = "NO" ]
rather than
if [ "$VAR" == "NO" ]
I'd also consider using egrep -o 'SI|NO' to leave out any other characters from the output of grep, if your copy has GNU extensions.
As another option, consider:
result=$(/home/userName/scripts/loadedresource.ksh)
case $result in
*SI*) echo "Yes" ;;
*NO*) echo "No" ;;
*) echo "Unknown" ;;
esac
As a performance enhancement, by the way:
{
echo "hello"
echo "world"
} >output.txt
...is considerably more efficient than
echo "hello" >output.txt
echo "world" >>output.txt
...which re-opens the output file once for each line.

Frustrated with simple awk command

I am trying to list out the contents of a field 1 using a function:
help(){
if [[ $# -eq 0 ]] ; then
echo '######################################'
echo ''
echo 'Argument to run run name must be given: ./report.sh Name'
echo 'Report names are:'
ALLNAMES=$(cut -d '|' -f 1 $CONFIGFILE | awk '{printf $0"\n"}')
echo $ALLNAMES
echo '######################################'
exit 0
fi
}
The output I get is :
$ bin/report.sh
######################################
Argument to run run name must be given: ./report.sh Name
Report names are:
ItemA ItemB
######################################
Whereas I want:
$ bin/report.sh
######################################
Argument to run run name must be given: ./report.sh Name
Report names are:
ItemA
ItemB
######################################
If I run the cut command I get:
[david#kallibu]$ cut -d '|' -f 1 conf/report.conf
ItemA
ItemB
Whatdo I need to change to get my newline ?
The problem is:
echo $ALLNAMES
Should be solved with quotes:
echo "$ALLNAMES"
If you're not goint to use the var ALLNAMES in other place, just:
help(){
if [[ $# -eq 0 ]] ; then
echo '######################################'
echo ''
echo 'Argument to run run name must be given: ./report.sh Name'
echo 'Report names are:'
cut -d '|' -f 1 conf/report.conf
echo '######################################'
exit 0
fi
}
Your code would be,
help(){
if [[ $# -eq 0 ]] ; then
echo '######################################'
echo ''
echo 'Argument to run run name must be given: ./report.sh Name'
echo 'Report names are:'
ALLNAMES=$(awk -F'|' '{print $1}' $CONFIGFILE)
echo "$ALLNAMES"
echo '######################################'
exit 0
fi
}
You could try this awk -F'|' '{print $1}' $CONFIGFILE command to get the value of first column where | as delimiter.
You need to put ALLNAMES inside double quotes. So that only, the ALLNAMES variable got expanded.
#Tiago provided the answer to your specific problem, but overall your script should either be the shell script #klashxx posted or this awk script:
help(){
if [[ $# -eq 0 ]] ; then
awk '
BEGIN {
FS = "|"
print "######################################\n"
print "Argument to run run name must be given: ./report.sh Name"
print "Report names are:"
}
{ print $1 }
END {
print "######################################"
}
' "$CONFIGFILE"
exit 0
fi
}
or similar.

bash check value is integer and in range

I read this stackoverflow question...
Bash: check user input is correct
which does most of what I want however rather then checking it's just an integer I need to check it's an integer in a variable range....
The script looks for files in a directory and then assigns a number to them...
File 1
File 2
File 3
etc....
The user chooses the the number and the script then executes commands against that file.....the variable $FILELIST is the total number of files.
Taking the example from the previous stackoverflow I tried.....
FILENUM=""
while [[ ! ($FILENUM =~ ^[0-$FILELIST]+$) ]]; do
echo " "
echo "Please enter the file number: "
read -p "1 - $FILELIST" FILENUM < /dev/tty
done
echo "$FILENUM"
However this is throwing a syntax error: unexpected "(" (expecting "do") in the while line and I'm not sure why, I suspect $FILELIST has to be bracketed somehow but an explanation as to why the above works would help me understand the problem.
Thanks
bash-specific answers:
You don't need to reinvent the wheel: use the select builtin:
cd /path/to/directory
PS3="Select a file: "
select file in *; do
if [[ $file ]]; then break; fi
done
echo "You selected '$file'"
echo "You selected file number $REPLY"
To check a number is within a certain range, I'd write:
if (( 0 <= $number && $number <= $max )); then echo "in range"; fi
Since you're using ash you might use this as a reference: http://manpages.debian.net/cgi-bin/man.cgi?query=dash
while true; do
FILENUM=""
echo
echo "Please enter the file number: "
read -p "1 - $FILELIST" FILENUM < /dev/tty
if expr "$FILENUM" : '[0-9]\+$' &&
[ $FILENUM -gt 0 ] &&
[ $FILENUM -le $FILELIST ]
then
break
fi
done
echo "$FILENUM"

Match pattern for variable in Shell Programming

it seems that I keep getting -gt or == error with the following. Can someone help?
flag= echo $flightSeatBooked | awk -F[,] '{print match($flightSeatBooked, $orderSeats)}'
if $flag == 0; then
echo "Success";
else
echo "fail";
Given:
flightSeatBooked= 9;,A1,A2,A3,A4,B2,E4,C3,B3,D3,D2,E1,E2,C2,B4,C4,D4,C1,D1,E3,B1
orderSeats= B2 (not found in the variable)
Expected output:
Success
Quite a few mistakes. Change it like this:
flag=$(echo $flightSeatBooked | awk -v flseat=$flightSeatBooked -v orseat=$orderSeats '{print match(flseat, orseat)}')
if [ $flag -eq 0 ]; then
echo "Success";
else
echo "fail";
fi
Command substitution has been done using the $(...) notation.
It is not a good practice to use the shell variables directly in awk, and hence passed shell variables to awk using -v.
The syntax of if used was incorrect, updated to correct it.
This is how to do what you ask:
flag=$(awk -v flseat="$flightSeatBooked" -v orseat="$orderSeats" 'BEGIN{print index(flseat, orseat)}')
if [ $flag -eq 0 ]; then
echo "Success"
else
echo "fail"
fi
BUT I don't think what you ask is a good idea. It at least should be something like this:
awk -v flseat="$flightSeatBooked" -v orseat="$orderSeats" 'BEGIN{exit index(flseat, orseat)}')
if [ $? -eq 0 ]; then
echo "Success"
else
echo "fail"
fi
and all you probably really need is something like this:
case "$flightSeatBooked" in
*"$orderSeats"* ) echo "fail";;
* ) echo "Success" ;;
esac
Check the logic (as I haven't!), but hopefully you get the approach.
You can also use this below to check whether $orderSeats is in $flightSeatBooked. If it is in then it return the length of string that matched or 0 is returned.
expr "$flightSeatBooked" : ".*,${orderSeats},"