This question already has an answer here:
Meaning of "=~" operator in shell script [duplicate]
(1 answer)
Closed 8 years ago.
I have come across this operator =~ and couldn't figure it out on what it does. Could someone with bash knowledge kindly help me out?
man bash
/=~
An additional binary operator, =~, is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an
extended regular expression and matched accordingly (as in regex(3)). The return value is 0 if the string matches the pattern, and 1 otherwise. If the regular
expression is syntactically incorrect, the conditional expression's return value is 2. If the shell option nocasematch is enabled, the match is performed without
regard to the case of alphabetic characters. Substrings matched by parenthesized subexpressions within the regular expression are saved in the array variable
BASH_REMATCH. The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression. The element of BASH_REMATCH with index n
is the portion of the string matching the nth parenthesized subexpression.
In ~ is saved your home directory (for example: /home/username) and = is assignment operator.
If you run this code in bash:
x=~ # variable x will hold string value /home/your_username
echo $x # print variable x via echo command
it will print something like: /home/your_username
Related
This question already has answers here:
What is the meaning of the ${0##...} syntax with variable, braces and hash character in bash?
(4 answers)
Closed 11 months ago.
I found the following code in a shell script, but I am unsure of what the test condition is evaluating for
if test "${SOME_VAR#*$from asdf/qwer}" != "$SOME_VAR"; then
echo "##zxcv[message text='some text.' status='NORMAL']";
fi
The combination #*$ does not mean anything special. There are three special symbols and each of them has its own meaning in this context.
${SOME_VAR#abc} is a parameter expansion. Its value is the value of $SOME_VAR with the shortest prefix that matches abc removed.
In your example, abc is *${from} asdf/qwer. That means anything * followed by the value of variable $from (which is dynamic and replaced when the expression is evaluated), followed by a space and followed by asdf/qwer.
All in all, if the value of $SOME_VAR starts with a string that ends in ${from} asdf/qwer then everything before and including asdf/qwer is removed and the resulting value is passed as the first argument to test.
Type man bash in your terminal to read the documentation of bash or read it online.
This question already has answers here:
What is the meaning of the ${0##...} syntax with variable, braces and hash character in bash?
(4 answers)
Closed 2 years ago.
I am learning the bash script materials on http://www.tldp.org/LDP/abs/html/index.html
and stuck in the Example 7-7:
http://tldp.org/LDP/abs/html/comparison-ops.html#EX14
There is an ${filename##*.} != "gz", this probably means
that the $filename does not end with .gz, but I do not
know the meaning of ## here. Could anyone help me?
Thanks!
Used in a variable expansion, ${string##sub} removes the longest matching substring sub from string (# removes the shortest matching substring by contrast).
In your case, yes - this will return the string after the first . from the filename, giving the file extension.
If you search for ## in this documentation, you'll find an explanation (along with other similar commands).
In the context of filenames, is trying to find the extension in the variable filename
filename="*.log"
echo ${filename##*.}
log
We are attaining the part of the string filename after "*."
## is a used for to remove a substring from a variable. For more info check this page.
For eg. if filename=/home/user.name/folder.1/test.gz, then ${filename##*.} will give you output as gz.
This question already has an answer here:
Bash: manipulating with strings (percent sign)
(1 answer)
Closed 6 years ago.
I've got the following variable set in bash:
ver=$(/usr/lib/virtualbox/VBoxManage -v | tail -1)
then I have the following variable which I do not quite understand:
pkg_ver="${ver%%r*}"
Could anyone elaborate on what this does, and how pkg_ver is related to the original ver value?
It is a bash parameter expansion syntax to extract text from end of string upto first occurrence of r
name="Ivory"
printf "%s\n" "${name%%r*}"
Ivo
${PARAMETER%%PATTERN}
This form is to remove the described pattern trying to match it from the end of the string. The operator "%" will try to remove the shortest text matching the pattern, while "%%" tries to do it with the longest text matching.
You will get everything from variable ver until first "r" character and it will be stored inside pkg_ver.
export ver=aaarrr
echo "${ver%%r*}"
aaa
i'm learning to touch type and I pressed ' [ ' instead of ' - ' . When I went on to the next line I couldn't do anything until i typed in k].
I then got a command not found error.
is this a 'apt-get' thing or something else?
Thanks.
This is not an apt-get thing, this is a shell thing.
As #rici says, if you were doing an assignment, then the [ ] notation would be used for array element modification. But you are not, so it isn't.
This is part of globbing, also known as wildcards, or filename expansion. The [ ] bracket notation is known as a character class, and is a range or list of alternative characters, matching one character in the filename. For example, [123] means "1" or "2" or "3", and could also be written as [1-3].
The thing about globbing is that (in bash) a failure to find a file which matches the pattern means that the literal is passed as a command. Assuming you did not have a file called apt[\n] in your current directory, it would try to execute a program by that name! (\n is a common notation for a new-line character).
Here is an example test script:
# Let's create some files
touch apt1 apt2 apt3
# Let's see the expansion
set -x
apt[
]
apt[
123
]
Here are the results, the + is the prompt (PS4) given by the xtrace (set -x):
+ 'apt[
]'
gash.sh: line 10: $'apt[\n]': command not found
So with the first one it was looking for a file with that pattern.
+ apt1 apt2 apt3
gash.sh: line 14: apt1: command not found
But with the second one the \n is treated as whitespace and it matches the filenames. apt1 is not a script in $PATH so it does not find it as a command.
You will notice that it has expanded to all the filenames that match, not just one.
It's because of the bash syntax for setting array elements.
If arr is an array variable,
arr[7]=Seventh
sets element 7 of the array to the string Seventh. So if bash is expecting a possible assignment, then it interprets word[ as a subscript operator, even if word is not a known array variable. (It will be created as an array variable if it is not already an array variable.)
Array subscripts are numeric contexts (unless the array has been declared as an associative array). In a numeric context, you can type an arithmetic expression without using $ as a variable sigil. In numeric contexts, whitespace is ignored, so the newline is ok.
Had apt been declared as an associative array, you could still assign an element using, for example,
apt[
key
]=42
However, in this case, the newlines are not ignored, so they become part of the key.
If there is no = following the ], then the word was not an array assignment, so it is treated as a word. But by then it has already been read, newlines and all. (Pathname expansion occurs after word-splitting, so bash will try to match the word with a filename in the current directory, using the characters, including the newline, between the [ and ] as a character class.)
For the following variable:
var="/path/to/my/document-001_extra.txt"
i need only the parts between the / [slash] and the _ [underscore].
Also, the - [dash] needs to be stripped.
In other words: document 001
This is what I have so far:
var="${var##*/}"
var="${var%_*}"
var="${var/-/ }"
which works fine, but I'm looking for a more compact substitution pattern that would spare me the triple var=...
Use of sed, awk, cut, etc. would perhaps make more sense for this, but I'm looking for a pure bash solution.
Needs to work under GNU bash, version 3.2.51(1)-release
After editing your question to talk about patterns instead of regular expressions, I'll now show you how to actually use regular expressions in bash :)
[[ $var =~ ^.*/(.*)-(.*)_ ]] && var="${BASH_REMATCH[#]:1:2}"
Parameter expansions like you were using previously unfortunately cannot be nested in bash (unless you use ill-advised eval hacks, and even then it will be less clear than the line above).
The =~ operator performs a match between the string on the left and the regular expression on the right. Parentheses in the regular expression define match groups. If a match is successful, the exit status of [[ ... ]] is zero, and so the code following the && is executed. (Reminder: don't confuse the "0=success, non-zero=failure" convention of process exit statuses with the common Boolean convention of "0=false, 1=true".)
BASH_REMATCH is an array parameter that bash sets following a successful regular-expression match. The first element of the array contains the full text matched by the regular expression; each of the following elements contains the contents of the corresponding capture group.
The ${foo[#]:x:y} parameter expansion produces y elements of the array, starting with index x. In this case, it's just a short way of writing ${BASH_REMATCH[1]} ${BASH_REMATCH[2]}. (Also, while var=${BASH_REMATCH[*]:1:2} would have worked as well, I tend to use # anyway to reinforce the fact that you almost always want to use # instead of * in other contexts.)
Both of the following should work correctly. Though the second is sensitive to misplaced characters (if you have a / or - after the last _ it will fail).
var=$(IFS=_ read s _ <<<"$var"; IFS=-; echo ${s##*/})
var=$(IFS=/-_; a=($var); echo "${a[#]:${#a[#]} - 3:2}")