I would like to check if that variable is in the correct date format or the variable is empty... if it is in the correct date format then i will perform sth
I have tried:
dada=2015-10-11
if [[ "$dada" = ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]
then echo "Date $dada is valid (YYYY-MM-DD)"
else echo "Date $dada is not invalid format (YYYY-MM-DD)"
fi
And also
if [ "`date '+%Y-%m-%d' -d $d 2>/dev/null`" = "$dada" ]
then echo "Date $dada is valid (YYYY-MM-DD)"
else echo "Date $dada is not invalid format (YYYY-MM-DD)"
fi
But it seems like it will always return and telling me that my format is incorrect.
$dada is a dynamic variable wherby it can be a number '444.1' , date format '2017-11-12' or a string 'hello this is not valid'
Converting an extensive set of comments into an answer.
How thorough a check do you want? Should the check reject 2015-02-29, for example?
2015-02-29 should be also rejected yup!
If you need to reject 2015-02-29, you're going to need much more checking than a single line — or the single line will be very long and complex and will have many alternatives in it.
The classic way to validate the data pattern would use the pattern matching from the case statement — maybe using something like this:
case "$dada" in
([12][0189][0-9][0-9]-[01][0-9]-[0-3][0-9]) : OK;;
(*) : Not OK;;
esac
but there are probably better modern ways of doing it. That mainly allows years 18xy, 19xy, 20xy, 21xy (though it does also let through 10xy, 11xy, 28xy, 29xy); you'll have to decide whether that's sensible. Similarly, it lets through months 13-19 (and 00), and days 32-39 (and 00); those are unconditionally invalid. Then you're left with "30 days hath September, …" to worry about.
If you removed the leading ( around the patterns, that statement would work in antique and archaic shells such as the Bourne shell. It isn't tied to Korn shell — it is standard notation in POSIX-like shells, and pre-POSIX shells.
How about just checking if the string format is in place like XXXX-XX-XX?
The case command I showed does a reasonable job for years in the range 1800 through 2199. But it is 'old school' notation. The merit is it works and I don't have to read the manual. Test it — change the : commands into echo.
I have tried the case but it seems like the code did not identify my data as a date. Is there any problem with my declaration of dada?
On my Mac, I was able to run (verbatim — a single line command):
ksh -c 'dada=2015-10-11; case "$dada" in ([12][0189][0-9][0-9]-[01][0-9]-[0-3][0-9]) echo OK;; (*) echo Not OK;; esac'
and I got OK as the output. For values such as 2215-10-11 and 2015-20-11, I got Not OK. It would be better, but isn't actually crucial, to use dada="2015-01-11"; instead of the unquoted form.
How about if I were to add a time at the back of the date — 2015-20-11 23:21? Can I write it as 'case "$HELLO" in ([0-3][0-9]/[01][0-9]/[0-9][0-9] [0-2][0-9]:[0-6][0-9])'
You could certainly add a glob expression that would match the time. I don't understand why the one you propose might be correct, but other patterns could be used.
For example:
dada="2015-11-20 23:21"
case "$dada" in
([12][0189][0-9][0-9]-[01][0-9]-[0-3][0-9]\ [012][0-9]:[0-5][0-9])
echo OK;;
(*) echo Not OK;;
esac
Note that the backslash is needed before the space in the pattern. When run with the data shown, the script reports OK. Change 23 to 32 and it reports Not OK.
There probably is a way to do this with the [[ command instead of writing out the case statement.
Doing more complex (thorough) validation using case is probably not a good idea. You'd do better to invoke a tool that validates dates properly. You might be able to use the (GNU) date command, or you could use Perl or Python or one of those scripting languages. These would reject 2015-02-29 23:21 but allow 2016-02-29 23:21 without problem.
dada=2015-10-11
date -d $dada > /dev/null 2>&1
[[ $? -eq 0 ]] && echo ok || echo not ok
Related
I am trying to write a bash script that will tell whether two strings are of similar value. I have produced this bash script:
#!/bin/bash
value="java.lang.NullPointerException"
if [[ "java.lang.NullPointerException" = "$value" || "java.lang.NullPointerException" == "$value"* ]]; then
echo "Match"
fi
Basically what I want to achive, is that if two strings are of equal value or a very similar either side but with matching text in the middle then echo "Match".
I have tried a number of resources but can't get this example to work. I have taken a look at:
In bash, how can I check if a string begins with some value?
How to test that a variable starts with a string in bash?
https://ubuntuforums.org/showthread.php?t=1118003
Please note these values would eventually come from a text file and so the values will be in a form of variables. I have tried different approaches, but don't seem to get it working. I just want to get this if statement working. It works for matching text but not for values either side. Value could be "java.lang.NullPointerException: Unexpected" or "Unexpected java.lang.NullPointerException".
#!/bin/bash
value="java.lang.NullPointerException" #or java.lang.NullPointerException: Unexpected
if [[ $value == *"java.lang.NullPointerException"* ]];
then
echo "Match"
fi
A simple and portable (POSIX compliant) technique for wildcard matching is to use a case statement rather than if. For your example, this would look something like
#!/bin/sh
value="java.lang.NullPointerException"
case "$value" in
*java.lang.NullPointerException*) echo Match;;
esac
I'm trying to write a short script that checks for verizon fios availability by zip code from a list of 5 digit us zip codes.
The basis of this I have working but comparing the recived output from curl to the expected output in the if statements isn't working.
I know there is a better & cleaner way to do this however I'm really interested in what is wrong with this method. I think it's something to do with the quotes getting jumbled up.
Let me know what you guys think. I originally thought this would be a quick little script. ha. Thanks for the help
Here is what I have so far:
#!/bin/bash
Avail='<link rel="canonical" href="http://fios.verizon.com/fios-plans.html#availability-msg" />'
NotAvail='<link rel="canonical" href="http://fios.verizon.com/order-now.html#availability-msg" />'
while read zip; do
chk=`curl -s -d "ref=GIa6uiuwP81j047HjKMHOwEyW4QJTYjG&PageID=page9765&AvailabilityZipCode=$zip" http://fios.verizon.com/availability_post4.php --Location | grep "availability-msg"`
#echo $chk
if [ "$chk" = "$Avail" ]
then
fios=1
elif [ "$chk" = "$NotAvail" ]
then
fios=0
else
fios=err
fi
echo "$zip | $fios"
done < zipcodes.txt
Most likely, the line read from curl ends in CR/LF. grep will take the LF as a line-end, and leave the CR in the line, where it will not match either of your patterns. (Other whitespace issues could also cause a similarly invisible mismatch, but stray CR's are very common since HTTP insists on them.)
The easiest solution is to use a less specific match, like a glob or regex; these are both available with bash's [[ (rather than [) command.
Eg.:
if [[ $chk =~ /fios-plans\.html ]]; then
will do a substring comparison
Sometimes I need to quote an entire command line for future evaluation. Usually I do that with:
printf "%q " "$#"
That's short and sweet but the output look awful. Most of the time this doesn't matter but in occasions I want to show it to the user. For example, in a history of executed commands menu that allows for re-execution of entries. That being the case, I would like to quote in a more readable form (closer to what the user itself would have done if he were in charge of quoting). So this:
search 'Wordreference (eng->spa)' utter
would be preferable to this:
search Wordreference\ \(eng-\>spa\) utter
In order to get the first quoted form I could iterate "$#" and do something like what follows for each argument:
[[ $arg == *\ * ]] && arg="'"${arg//\'/\'\\\'\'}"'"
This is not difficult at all but it involves a loop, a conditional string transformation and concatenation of the result of each iteration.
I wonder if there is a more "batteries included" command to do this kind of transformation out of the box.
In the same way you use eval to later execute the string, you can use eval to print it:
eval "echo $yourstring"
This will remove the shell escapes but keep your variable intact.
I was reading though this other question which has some really good regex's for the job but as far as I can see non of them work with BASH commands as BASH commands don't support such complex rexeg's.
if echo "http://www.google.com/test/link.php" | grep -q '(https?|ftp|file)://[-A-Z0-9\+&##/%?=~_|!:,.;]*[-A-Z0-9\+&##/%=~_|]'; then
echo "Link valid"
else
echo "Link not valid"
fi
But this doesn't work as grep -q doesn't work ...
Edit, ok I just realised that grep had an "extended-regex" (-E) option which seems to make it work. But if anyone has a better/faster way I would still love to here about it.
The following works in Bash >= version 3.2 without using grep:
regex='(https?|ftp|file)://[-[:alnum:]\+&##/%?=~_|!:,.;]*[-[:alnum:]\+&##/%=~_|]'
string='http://www.google.com/test/link.php'
if [[ $string =~ $regex ]]
then
echo "Link valid"
else
echo "Link not valid"
fi
I simplified your regex by using [:alnum:] which also matches any alphanumeric character (e.g. Э or ß), but support varies by the underlying regex library. This is another potential simplification which uses + instead of * and a repeated sequence (although your second sequence is different from the first).
regex='(https?|ftp|file)://[-[:alnum:]\+&##/%?=~_|!:,.;]+'
Since I don't have enough rep to comment above, I am going to amend the answer given by Dennis above with this one.
I incorporated Christopher's update to the regex and then added more to it so that the URL has to at least be in this format:
http://w.w (has to have a period in it).
And tweaked output a bit :)
regex='^(https?|ftp|file)://[-A-Za-z0-9\+&##/%?=~_|!:,.;]*[-A-Za-z0-9\+&##/%=~_|]\.[-A-Za-z0-9\+&##/%?=~_|!:,.;]*[-A-Za-z0-9\+&##/%=~_|]$'
url='http://www.google.com/test/link.php'
if [[ $url =~ $regex ]]
then
echo "$url IS valid"
else
echo "$url IS NOT valid"
fi
Probably because the regular expression is written in PCRE syntax. See if you have (or can install) the program pcregrep on your system - it has the same syntax as grep but accepts Perl-compatible regexes - and you should be able to make that work.
Another option is to try the -P option to grep, but the man page says that's "highly experimental" so it may or may not actually work.
I will say that you should think carefully about whether it's really appropriate to be using this or any regex to validate a URL. If you want to have a correct validation, you'd probably be better off finding or writing a small script in, say, Perl, to use the URL validation facilities of the language.
EDIT: In response to your edit in the question, I didn't notice that that regex is also valid in "extended" syntax. I don't think you can get better/faster than that.
I'm not entirely new to programming, but I'm not exactly experienced. I want to write small shell script for practice.
Here's what I have so far:
#!/bin/sh
name=$0
links=$3
owner=$4
if [ $# -ne 1 ]
then
echo "Usage: $0 <directory>"
exit 1
fi
if [ ! -e $1 ]
then
echo "$1 not found"
exit 1
elif [ -d $1 ]
then
echo "Name\t\tLinks\t\tOwner\t\tDate"
echo "$name\t$links\t$owner\t$date"
exit 0
fi
Basically what I'm trying to do is have the script go through all of the files in a specified directory and then display the name of each file with the amount of links it has, its owner, and the date it was created. What would be the syntax for displaying the date of creation or at least the date of last modification of the file?
Another thing is, what is the syntax for creating a for loop? From what I understand I would have to write something like for $1 in $1 ($1 being all of the files in the directory the user typed in correct?) and then go through checking each file and displaying the information for each one. How would I start and end the for loop (what is the syntax for this?).
As you can see I'm not very familiar bourne shell programming. If you have any helpful websites or have a better way of approaching this please show me!
Syntax for a for loop:
for var in list
do
echo $var
done
for example:
for var in *
do
echo $var
done
What you might want to consider however is something like this:
ls -l | while read perms links owner group size date1 date2 time filename
do
echo $filename
done
which splits the output of ls -l into fields on-the-fly so you don't need to do any splitting yourself.
The field-splitting is controlled by the shell-variable IFS, which by default contains a space, tab and newline. If you change this in a shell script, remember to change it back. Thus by changing the value of IFS you can, for example, parse CSV files by setting this to a comma. this example reads three fields from a CSV and spits out the 2nd and 3rd only (it's effectively the shell equivalent of cut -d, -f2,3 inputfile.csv)
oldifs=$IFS
IFS=","
while read field1 field2 field3
do
echo $field2 $field3
done < inputfile.csv
IFS=oldifs
(note: you don't need to revert IFS, but I generally do to make sure that further text processing in a script isn't affected after I'm done with it).
Plenty of documentation out the on both for and while loops; just google for it :-)
$1 is the first positional parameter, so $3 is the third and $4 is the fourth. They have nothing to do with the directory (or its files) the script was started from. If your script was started using this, for example:
./script.sh apple banana cherry date elderberry
then the variable $1 would equal "apple" and so on. The special parameter $# is the count of positional parameters, which in this case would be five.
The name of the script is contained in $0 and $* and $# are arrays that contain all the positional parameters which behave differently depending on whether they appear in quotes.
You can refer to the positional parameters using a substring-style index:
${#:2:1}
would give "banana" using the example above. And:
${#: -1}
or
${#:$#}
would give the last ("elderberry"). Note that the space before the minus sign is required in this context.
You might want to look at Advanced Bash-Scripting Guide. It has a section that explains loops.
I suggest to use find with the option -printf "%P\t%n\t%u\t%t"
for x in "$#"; do
echo "$x"
done
The "$#" protects any whitespace in supplied file names. Obviously, do your real work in place of "echo $x", which isn't doing much. But $# is all the junk supplied on the command line to your script.
But also, your script bails out if $# is not equal to 1, but you're apparently fully expecting up to 4 arguments (hence the $4 you reference in the early part of your script).
assuming you have GNU find on your system
find /path -type f -printf "filename: %f | hardlinks: %n| owner: %u | time: %TH %Tb %TY\n"