I am using the if-extra for ModX. Is it possible to use mutliple operands, meaning write this code in a shorter way:
[[!If?
&subject=`[[!getUrlParam? &name=`id`]]`
&operator=`EQ`
&operand=`1`
&then=`do something`
]]
[[!If?
&subject=`[[!getUrlParam? &name=`id`]]`
&operator=`EQ`
&operand=`2`
&then=`do something`
]]
[[!If?
&subject=`[[!getUrlParam? &name=`id`]]`
&operator=`EQ`
&operand=`3`
&then=`do something`
]]
Couldn't find a way to do it.
Try https://modx.com/extras/package/switch extra.
[[!switch?
&get=`[[!getUrlParam? &name=`id`]]`
&c1=`1`
&do1=`do something1`
&c2=`2`
&do2=`do something2`
&c3=`3`
&do3=`do something3`
&default=`default value`
]]
I could work with this solution:
[[If?
&subject=`[[!getUrlParam? &name=`id`]]`
&operator=`inarray`
&operand=`1,2,3`
&then=`do something`
]]
Related
I'm working on a bash script to rename automatically files on my Synology NAS.
I have a loop for the statement of the files and everything is ok until I want to make my script more efficient with regex.
I have several bits of code which are working like as expected:
filename="${filename//[-_.,\']/ }"
filename="${filename//[éèēěëê]/e}"
But I have this:
filename="${filename//t0/0}"
filename="${filename//t1/1}"
filename="${filename//t2/2}"
filename="${filename//t3/3}"
filename="${filename//t4/4}"
filename="${filename//t5/5}"
filename="${filename//t6/6}"
filename="${filename//t7/7}"
filename="${filename//t8/8}"
filename="${filename//t9/9}"
And, I would like to use captured group to have something like this:
filename="${filename//t([0-9]{1,2})/\1}"
filename="${filename//t([0-9]{1,2})/${BASH_REMATCH[1]}}"
I've been looking for a working syntax without success...
The shell's parameter expansion facility does not support regular expressions. But you can approximate it with something like
filename=$(sed 's/t\([0-9]\)/\1/g' <<<"$filename")
This will work regardless of whether the first digit is followed by additional digits or not, so dropping that requirement simplifies the code.
If you want the last or all t[0-9]{1,2}s replaced:
$ filename='abt1cdt2eft3gh'; [[ "$filename" =~ (.*)t([0-9]{1,2}.*) ]] && filename="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"; echo "$filename"
abt1cdt2ef3gh
$ filename='abt1cdt2eft3gh'; while [[ "$filename" =~ (.*)t([0-9]{1,2}.*) ]]; do filename="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"; done; echo "$filename"
ab1cd2ef3gh
Note that the "replace all" case above would keep iterating until all t[0-9]{1,2}s are changed, even ones that didn't exist in the original input but were being created by the loop, e.g.:
$ filename='abtt123de'; while [[ "$filename" =~ (.*)t([0-9]{1,2}.*) ]]; do filename="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"; echo "$filename"; done
abt123de
ab123de
whereas the sed script in #tripleee's answer would not do that:
$ filename='abtt123de'; filename=$(sed 's/t\([0-9]\)/\1/g' <<<"$filename"); echo "$filename"
abt123de
I receive a string that can be either all numeric dash-separated, and in that case it is acceptable to me (e.g. 123423-56788-456522-34245) or not all numeric and still dash-separated, and in that case it is not acceptable to me (e.g. 123423-56788-shelve-34245).
In order to determine whether the string is acceptable or not, I have built the following if block:
REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS='^[0-9-]+$'
if [[ ${BUILD_ID} =~ ${REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS} ]]
then
echo true
else
echo false
fi
The above if block works fine. However, if I would be programming into another language (for example, Java), I would be assigning the evaluation directly into the variable. For example:
int a = 3;
int b = 5;
boolean test = (a < b);
The above test would be true: I would be evaluating the expression (a < b) and store its result into the variable test in one line.
I would like to know if it is possible to do the same in Bash. Looking around the web, I haven't found many examples. Thanks to this answer, I have realized that if I do this:
bash$ false_expression=$((2 == 4))
bash$ true_expression=$((2 == 2))
... the two variables assume values 0 and 1 respectively. It's not exactly true or false, but I could still accept it.
However, I don't seem to be able to do the same with my expression because if I do this:
InvalidCL=123423-56788-shelve-34245
MyRegex='^[0-9-]+$'
FalseExpression=$((${InvalidCL} =~ ${MyRegex}))
...the third assignment raises this error:
-bash: 123423-56788-shelve-34245 =~ ^[0-9-]+$: attempted assignment to non-variable (error token is "=~ ^[0-9-]+$")
I'm not a real bash expert, so my question (hoping it's not too silly) is: is it possible to assign the evaluation to a variable? I can see that my if [[ myExpression ]] is evaluated as true, so I don't understand why I wouldn't be able to assign this evaluation to a variable... Can anyone explain please?
If you really want to do it with one assignment then you could do it like:
FalseExpression=$( [[ "$InvalidCL" =~ $MyRegex ]] && echo 1 || echo 0)
where 1 stands for true and 0 for false. Keep in mind, though, that this is not the traditional Bash way. A result of 0 in Bash indicates no error, i.e., if the expression evaluates to true then you get an exit status of:
$ echo $?
0
Notice, the use of single ( which stand for command substitution, whereas the (( in your example evaluate a mathematical expression.
Traditionally, one would probably do it like this:
$ [[ "$InvalidCL" =~ $MyRegex ]]
$ FalseExpression=$?
Bash stores the exit status of the last opereation in '$?', which behaves in an opposite way as the $(()) operator. If the expression is true than $? will store 0 while $(()) will return 1. The latter is probably more familiar if you are coming from a C background. I suggest to not mix those approaches. It can be quite hard to debug a script if one result can have different meanings.
You could also do:
[[ ${BUILD_ID} =~ ${REGEX_FOR_ONLY_NUMERICAL_CHANGELISTS} ]]
val=$?
to avoid invoking a subshell. Again, val is 0 on success and 1 on failure.
Others have already pointed out how to work around getting the boolean return value of the regular expression match.
Regarding the phrasing of the actual question, I would like to point out that the evaluation results of a regex expression actually automatically get stored in an environment variable in bash. The $BASH_REMATCH array stores the entire match at index 0 and the capturing groups at their respective indices. See: https://www.linuxjournal.com/content/bash-regular-expressions
The number of elements in this array can also, perhaps more comfortably than the manual assignment from $?, be used as an indicator of success of the match. If ${#BASH_REMATCH[*]} is zero, the last regular expression did not match.
You get the error message you cited because regular expression matching syntax is defined only within the [[ ... ]] construct, not in $(( ... ))arithmetic evaluation, so when it sees the = it thinks you must be trying some sort of assignment.
If you want a direct single-line assignment to a numeric boolean, you can use a "not" operator in your test.
I strongly recommend you add some explanatory comments around this.
# assign an integer BOOLEAN value from the test for a match
# the ! means NOT, inverts a 0/1 OS exit code from [[ ]]
match="$( [[ ! "$string" =~ $pattern ]]; echo $?; )"
# now $match is 1 (TRUE) if it *matched* the pattern
For better clarity, make a function with the comments in it to encapsulate the logic, and call that from one line.
boolMatch() {
local match str="$1" pat="$2"
# test the match
[[ "$str" =~ $pat ]]
# invert the return to a boolean value
match=$(( ! $? ))
# pass back the boolean
echo $match
}
$: boolMatch foo bar
0
$: boolMatch foo foo
1
$: match=$( boolMatch $stringToCheck $patternToUse )
In a bash script I have to match strings that begin with exactly 3 times with the string lo; so lololoba is good, loloba is bad, lololololoba is good, balololo is bad.
I tried with this pattern: "^$str1/{$n,}" but it doesn't work, how can I do it?
EDIT:
According to OPs comment, lololololoba is bad now.
This should work:
pat="^(lo){3}"
s="lolololoba"
[[ $s =~ $pat ]] && echo good || echo bad
EDIT (As per OPs comment):
If you want to match exactly 3 times (i.e lolololoba and such should be unmatched):
change the pat="^(lo){3}" to:
pat="^(lo){3}(l[^o]|[^l].)"
You can use following regex :
^(lo){3}.*$
Instead of lo you can put your variable.
See demo https://regex101.com/r/sI8zQ6/1
You can use this awk to match exactly 3 occurrences of lo at the beginning:
# input file
cat file
lololoba
balololo
loloba
lololololoba
lololo
# awk command to print only valid lines
awk -F '^(lo){3}' 'NF == 2 && !($2 ~ /^lo/)' file
lololoba
lololo
As per your comment:
... more than 3 is bad so "lolololoba" is not good!
You'll find that #Jahid's answer doesn't fit (as his gives you "good" to that test string.
To use his answer with the correct regex:
pat="^(lo){3}(?\!lo)"
s="lolololoba"
[[ $s =~ $pat ]] && echo good || echo bad
This verifies that there are three "lo"s at the beginning, and not another one immediately following the three.
Note that if you're using bash you'll have to escape that ! in the first line (which is what my regex above does)
My code have problem with compare var with regular expression.
The main problem is problem is here
if [[ “$alarm” =~ ^[0-2][0-9]\:[0-5][0-9]$ ]]
This "if" is never true i dont know why even if i pass to "$alarm" value like 13:00 or 08:19 its always false and write "invalid clock format".
When i try this ^[0-2][0-9]:[0-5][0-9]$ on site to test regular expressions its work for example i compered with 12:20.
I start my script whith command ./alarm 11:12
below is whole code
#!/bin/bash
masa="`date +%k:%M`"
mp3="$HOME/Desktop/alarm.mp3" #change this
echo "lol";
if [ $# != 1 ]; then
echo "please insert alarm time [24hours format]"
echo "example ./alarm 13:00 [will ring alarm at 1:00pm]"
exit;
fi
alarm=$1
echo "$alarm"
#fix me with better regex >_<
if [[ “$alarm” =~ ^[0-2][0-9]\:[0-5][0-9]$ ]]
then
echo "time now $masa"
echo "alarm set to $alarm"
echo "will play $mp3"
else
echo "invalid clock format"
exit;
fi
while [ $masa != $alarm ];do
masa="`date +%k:%M`" #update time
sleep 1 #dont overload the cpu cycle
done
echo $masa
if [ $masa = $alarm ];then
echo ringggggggg
play $mp3 > /dev/null 2> /dev/null &
fi
exit
I can see a couple of issues with your test.
Firstly, it looks like you may be using the wrong kind of double quotes around your variable (“ ”, rather than "). These "fancy quotes" are being concatenated with your variable, which I assume is what causes your pattern to fail to match. You could change them but within bash's extended tests (i.e. [[ instead of [), there's no need to quote your variables anyway, so I would suggest removing them entirely.
Secondly, your regular expression allows some invalid dates at the moment. I would suggest using something like this:
re='^([01][0-9]|2[0-3]):[0-5][0-9]$'
if [[ $alarm =~ $re ]]
I have deliberately chosen to use a separate variable to store the pattern, as this is the most widely compatible way of working with bash regexes.
I'm new to shell scripting and trying to write the ability to check if an argument exists and if it matches an expression. I'm not sure how to write expressions, so this is what I have so far:
#!/bin/bash
if [[ -n "$1"] && [${1#*.} -eq "tar.gz"]]; then
echo "Passed";
else
echo "Missing valid argument"
fi
To run the script, I would type this command:
# script.sh YYYY-MM.tar.gz
I believe what I have is
if the YYYY-MM.tar.gz is not after script.sh it will echo "Missing valid argument" and
if the file does not end in .tar.gz it echo's the same error.
However, I want to also check if the full file name is in YYYY-MM.tar.gz format.
if [[ -n "$1" ]] && [[ "${1#*.}" == "tar.gz" ]]; then
-eq: (equal) for arithmetic tests
==: to compare strings
See: help test
You can also use:
case "$1" in
*.tar.gz) ;; #passed
*) echo "wrong/missing argument $1"; exit 1;;
esac
echo "ok arg: $1"
As long as the file is in the correct YYYY-MM.tar.gz format, it obviously is non-empty and ends in .tar.gz as well. Check with a regular expression:
if ! [[ $1 =~ [0-9]{4}-[0-9]{1,2}.tar.gz ]]; then
echo "Argument 1 not in correct YYYY-MM.tar.gz format"
exit 1
fi
Obviously, the regular expression above is too general, allowing names like 0193-67.tar.gz. You can adjust it to be as specific as you need it to be for your application, though. I might recommend
[1-9][0-9]{3}-([1-9]|10|11|12).tar.gz
to allow only 4-digit years starting with 1000 (support for the first millennium ACE seems unnecessary) and only months 1-12 (no leading zero).