following script works as expected on my Ubuntu 16.04 shell:
Teststring="1234a5"
re='^[0-9]+$'
if ! [[ $TestString =~ $re ]]; then
echo "is not a number"
exit 1
fi
On my target although, I have only busybox instead of a full blown shell and it raises following error:
ash: =~: unknown operand
How do I make it work with busybox?
Background: I have a busybox script that wants to read a number from a special file on the system, do some calculations with it and writing the result out to a different file.
Before running into "not a number"-Errors later, I want to do a propper check bevorehand.
With external tools
egrep
if ! echo "$Teststring" | egrep -q "$re"; then
or modifying re
re='[0-9]\+'
if ! expr "$Teststring" : "$re"; then
using builtin shell expansion
in that particular case: if string is empty or contains a non digit
case $Teststring in
''|*[!0-9]*)
echo "is not a number"
;;
esac
Related
I have a bash script that has a function like so:
sanitize(){
rb_reg="^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$"
if grep -Ex "${rb_reg}" "${1}/.ruby-version" > /dev/null 2>&1; then
sanitize_tmp="$(<"${1}"/.ruby-version)" &&
ruby_version="${sanitize_tmp//[^0-9\.]/}" &&
echo "Setting Ruby Version: ${ruby_version}"
else
echo "There was an error trying to sanitize a .ruby-version file"
echo "The file was: ${1}/.ruby-version"
exit 7
fi
}
I'm using it to check a .ruby-version file and then set the version in there as a variable.
Mostly these files will contain something sensible like: 2.0.0 which works OK. I want to be defensive and not trust the input file, so check/sanitize it as much as possible.
Two questions:
If for some reason there were multiple version numbers in the file on multiple lines, say:
'2.0.0
1.0.0'
That's going to smash them together currently removing white space and end up with a variable like: '2.0.01.0.0'
What's a good way to only pick up the first version number that matches the regex?
Is there a better way to do this, maybe entirely in bash without grep? Appreciate any examples people have of checking for a version like this but not trusting the input file.
I'm still playing around with this a little, but here is what I ended up doing.
I'm passing in the file name as an argument to the function elsewhere in the script. Really liked the concept of BASH_REMATCH, so tried to avoid using grep, sed, awk etc and do it this way.
You can view the latest version of the code here: https://github.com/octopusnz/scripts
sanitize(){
if [[ "${#}" -ne 1 ]]; then
echo "[ERROR 7]: We expected 1 argument to the sanitize() function."
echo "But we got ${#} instead."
exit 7
fi
rbv_reg="^([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{1,2})(-([a-z]{1,10}))?$"
reg_matches=0
while read -r rbv_line || [[ -n "$rbv_line" ]]; do
if [[ "${rbv_line}" =~ ${rbv_reg} ]]; then
ruby_version="${BASH_REMATCH[0]//[^0-9a-z\.\-]/}" &&
((reg_matches="${reg_matches}"+1)) &&
echo "" &&
echo "Setting Ruby version: ${ruby_version}" &&
break
fi
done < "${1}"
if [[ "${reg_matches}" -lt 1 ]]; then
if [[ -v ruby_version ]]; then
echo "We couldn't parse ${1} and set a valid Ruby version."
echo "Using default: ${ruby_version}"
else
echo "We couldn't parse ${1} and set a default Ruby version."
echo "[ERROR 4]: No valid .ruby-version file found."
exit 4
fi
fi
}
So i am running a bash script in coreos and thus I do not have /bin/bash however I do have /bin/sh. Now sh has been fine until I was using someone elses bash script and they have the following line.
if [[ "$file" =~ ^https?:// ]]; then
and my os complained with sh: =~: unknown operand now i assume this mean that the ~= opeator is not compatible with sh but there has to be some other way to do this form looking on SO I discovered that ~= is sometype of regular expressions operator. My question is this then can I replace ~= with something? Note: I have grep on my machine.
I have grep on my machine
Going by the above line, you could write a simple conditional using an if statement as
if echo "$file" | grep -Eq "^https?://"; then
printf 'regex matches\n'
fi
The regex match in grep uses ERE (Extended Regular Expressions) which is available in any POSIX compliant grep that you have installed. The -q just suppresses the normal stdout printed but just returns an exit code to know if the match was successful.
Even if some package of grep you have doesn't have -E allowed, just use the basic regular expressions support, but deprive ? of its special value and pass it literally
if echo "$file" | grep -q "^https\?://"; then
You could rewrite this as a case command:
case "$file" in
http://* | https://* )
# ...
;;
esac
You can call out to expr which does basic regex matching:
if expr match "$file" 'https\?://'; then
The pattern is implicitly anchored to the start of the string.
I am a first year Computer technician student, and before now have never actually used linux. I grasped the basics of scripting fairly quickly and am trying to write a script that will create a directory and a soft link for each assignment. seeing as we average two assignments a week i thought this would be helpful.
I am having trouble making my script accept only numbers as variables. I have it mostly working (mostly) with use of 3 case statements, but would rather use basic regex with an if statement, if I can.
if [ $# != 1 ]; then
red='\033[0;31m'
NC='\033[0m'
blue='\033[1;34m'
NC='\033[0m'
echo 1>&2 "${blue}ERROR:${NC} $0 :${red}expecting only one variable, you gave $#($*)${NC}"
echo 1>&2 "${blue}Usage:${NC} $0 :${red}number of assignment.${NC}"
exit 2
fi
case $1 in
[[:punct:]]*) echo 1>&2 "Numeric Values Only"
exit 2
;;
[[:alpha:]]*) echo 1>&2 "Numeric Values Only"
exit 2
;;
[[:space:]]*) echo 1>&2 "Numeric Values Only"
exit 2
;;
esac
the script then makes the directory and creates a soft link for the marking script (if its posted), and ends. can anyone help me shorten/eliminate the case statements
You cannot use regular expressions in portable shell scripts (ones that will run on any POSIX compliant shell). In general, patterns in the shell are globs, not regular expressions.
That said, there are a few other options. If you are using Bash specifically, you have two choices; you can use extended globs, which give you some regex like functionality:
shopt -s extglob
case $1 in
+([[:digit:]]) ) echo "digits" ;;
*) echo "not digits" ;;
esac
Another option is that Bash has the =~ operator in the [[ ]] conditional construct to match strings against a regex; this doesn't work in a case statement, but works in an if:
if [[ $1 =~ [0-9]+ ]]
then
echo "digits"
fi
Finally, if you want to do regular expression matching portably (so it will run in other POSIX shells like ash, dash, ksh, zsh, etc), you can call out to grep; if you pass -q, it will be silent about the matches but return success or failure depending on whether the input matched:
if echo "$1" | grep -qE "[0-9]+"
then
echo "digits"
fi
my programs starts some services and store its output in tmp variable and I want to match the variable's content if it starts with FATAL keyword or not? and if it contains I will print Port in use using echo command
For example if tmp contains FATAL: Exception in startup, exiting.
I can do it by sed: echo $tmp | sed 's/^FATAL.*/"Port in use"/'
but I want to use the builtin if to match the pattern.
How can I use the shell built in features to match REGEX?
POSIX shell doesn't have a regular expression operator for UNIX ERE or PCRE. But it does have the case keyword:
case "$tmp" in
FATAL*) doSomethingDrastic;;
*) doSomethingNormal;;
esac
You didn't tag the question bash, but if you do have that shell you can do some other kinds of pattern matching or even ERE:
if [[ "$tmp" = FATAL* ]]; then
…
fi
or
if [[ $tmp =~ ^FATAL ]]; then
…
fi
if [ -z "${tmp%FATAL*}" ]
then echo "Start with"
else
echo "Does not start with"
fi
work on KSH, BASH under AIX. Think it's also ok under Linux.
It's not a real regex but the limited regex used for file matching (internal to the shell, not like sed/grep/... that have their own version inside) of the shell. So * and ? could be used
Trying out fish shell, so I'm translating my bash functions. The problem is that in one case, I'm using bash regexes to check if a string matches a regex. I can't figure out how to translate this into fish.
Here is my example.
if [[ "$arg" =~ ^[0-9]+$ ]]
...
I looked into sed, but I don't see a way to get it to set its exit status based on whether the regex matches.
I looked into delegating to Ruby, but again, getting the exit status set based on the match requires making this really ugly (see below).
I looked into delegating back to bash, but despite trying maybe three or four ways, never got that to match.
So, is there a way in *nix to check if a string matches a regex, so I can drop it into a conditional?
Here is what I have that currently works, but which I am unhappy with:
# kill jobs by job number, or range of job numbers
# example: k 1 2 5
# example: k 1..5
# example: k 1..5 7 10..15
# example: k 1-5 7 10-15
function k
for arg in $argv
if ruby -e "exit ('$arg' =~ /^[0-9]+\$/ ? 0 : 1)"
kill -9 %$arg
else
set _start (echo "$arg" | sed 's/[^0-9].*$//')
set _end (echo "$arg" | sed 's/^[0-9]*[^0-9]*//')
for n in (seq $_start $_end)
kill -9 %"$n"
end
end
end
end
The standard way is to use grep:
if echo "$arg" | grep -q -E '^[0-9]+$'
kill -9 %$arg
I would suggest to use the built-in string match subcommand
if string match -r -q '^[0-9]+$' $arg
echo "number!"
else
echo "not a number"
end
Starting from version 3.2, Bash natively supports regexs, see http://www.tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF