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
Related
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.
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
In GNU sed, I can display the result of successful substitution of the search pattern. Simple example as the following:
echo -e "nginx.service\nmariadb.service\nphp-fpm.service" > something.conf;
sed -ri 's|(mariadb)(\.service)|postgresql-9.4\2|w sed-output.log' something.conf;
[[ -s sed-output.log ]] && echo "Pattern found and modified. $(cat sed-output.log)" || echo "Pattern not found.";
Because sed has limitation while dealing with multilines, I switched to perl.
echo -e "nginx.service\nmariadb.service\nphp-fpm.service" > something.conf;
perl -i -pe 's|(mariadb)(\.service)|postgresql-9.4\2|' something.conf;
The code above did the same like sed, but how can I get the modified content ("postgresql-9.4.service") into a file, or printed out?
Basically what I would like to achieve is, after the script has been executed, it tells me if it's successful (and what actually substituted) and if not, I'll display a message of what couldn't be found and replaced.
Edit:
Highlighted that I want to get (only-the-) modified content, which indicates that my script is successful. Because with perl -i -pe 's/pattern/replace/' file, I couldn't know if it return true or false. Of course I can simple do grep -E "/pettern/" to find out, but that's not the question.
This code will throw an exit code equal to 0 when replacement is done:
$ perl -i -pe '$M += s|(mariadb)(\.service)|postgresql-9.4\2|;END{exit 1 unless $M>0}' something.conf
$ echo $?
0
When NO substitution is done, return code will be 1:
$ perl -i -pe '$M += s|(maria)(\.service)|postgresql-9.4\2|;END{exit 1 unless $M>0}' something.conf
$ echo $?
1
From Perl documentation
An END code block is executed as late as possible, that is, after perl
has finished running the program and just before the interpreter is
being exited, even if it is exiting as a result of a die() function.
(But not if it's morphing into another program via exec, or being
blown out of the water by a signal--you have to trap that yourself (if
you can).) You may have multiple END blocks within a file--they will
execute in reverse order of definition; that is: last in, first out
(LIFO). END blocks are not executed when you run perl with the -c
switch, or if compilation fails.
Number of replacements returned from s operator
s/PATTERN/REPLACEMENT/msixpodualngcer
Searches a string for a pattern, and if found, replaces that pattern
with the replacement text and returns the number of substitutions
made.
It isn't as tidy in Perl because you have to open your log file explicitly, and for a one-liner that has to be in a BEGIN block. But Perl's s/// returns the number of changes made, so you can test it for truth
Note also that $2 is better than \2 in Perl, as the latter represents a character with code point 2, or Unicode U+0002 START OF TEXT
perl -i -pe ' BEGIN { open F, ">perl-output.log" } print F $_ if s|(mariadb)(\.service)|postgresql-9.4$2| ' something.conf
You can check the output directly if you only print the substituted lines:
if [[ -z $(sed -n 's/mariadb\(\.service\)/postgresql-9.4\1/p' something.conf) ]]; then
echo nope
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