I have output from VBoxManage list vms
which looks like this:
"arch" {de1a1db2-86c5-43e7-a8de-a0031835f7a7}
"arch2" {92d8513c-f13e-41b5-97e2-2a6b17d47b67}
I need to grab the names arch
and arch2
and save them into a variable.
This will parse the contents of those 2 strings:
$ grep -o '".*"' somefile | sed 's/"//g'
arch
arch2
The above looks for a string matching the pattern ".*"
. That will match anything that occurs within double quotes. So grep
will return these types of values:
"arch"
"arch2"
The pipe to sed
will strip off any double quotes from these strings giving your the strings you're looking for. The notation sed 's/"//g'
is instructing sed
to do a search and replace on all occurrences of double quotes, substituting them with nothing, s/"//g
. The command s/find/replace/g
is what's going on there, and the trailing g
to search tells it to do it globally on the entire string that it's given.
You can also use sed
to chop off the beginning double quote, keep what's in between them, and chop off the remaining quote + everything there after:
$ sed 's/^"\(.*\)".*/\1/' a
arch
arch2
$ grep -o '".*"' somefile | tr -d '"'
arch
arch2
The command tr
can be used to delete characters. In this case it's deleting the double quotes.
$ grep -oP '(?<=").*(?=")' somefile
arch
arch2
Using grep
's PCRE feature you can look for any substrings that begin with a double quote or end with a double quote and report just the substring.
tr -d \"
is another way to delete the quotes. (tr
normally translates one set of characters into another; -d
tells it to just delete them instead.)
/address/
to sed
like sed '/^"\(arch[^"]*\)/s//\1/
you'll only operate on lines containing that string.
sed
really should be doing s/^"\([^"]*\)".*/\1/
just in case there are than only two double-quotes on the line.
That's another job for cut
:
VBoxManage list vms | cut -d \" -f2
cut
splits each line into fields using the quote mark as delimiter, then outputs field 2: field 1 is the empty string before the first quote, field 2 is the wanted string between the quotes, and field 3 is the rest of the line.
With sed
you can do:
var=$(VBoxManage list vms | sed 's/^"\([^"]*\).*/\1/')
Explanation:
s/.../.../
- match and replace^
- match at start of line\(...\)
- this is a back reference, we can refer to what is matched in here later with \1
[^"]*
- match any sequence that does not contain a "
(ie up to the the next "
).*
- match the rest of the line\1
- replace with the back referenceOr with awk
:
var=$(VBoxManage list vms | awk -F\" '{ print $2 }')
Note that in modern shells you can also use an array instead of a normal variable. In bash
you can do:
IFS=$'\n'; set -f
array=( $(VBoxManage list vms | awk -F\" '{ print $2 }') )
echo "array[0] = ${array[0]}"
echo "array[1] = ${array[1]}"
This might be easier when you come to use the variable.
And the one through grep oneliner with --perl-regexp
option,
VBoxManage list vms | grep -oP '(?<=^\")[^"]*'
Explanation:
(?<=^\")[^"]*
-> A lookbehind is used here. It matches any character but not of "
zero or more times(once it find a double quotes, it stops matching) which are just after double quotes(only the line that starts with double quotes).
Another Ugly hack through sed
,
$ sed '/.*\"\(.*\)\".*/ s//\1/g' file
arch
arch2
Using bash, I'd write:
while read vm value; do
case $vm in
'"arch"') arch=$value ;;
'"arch2"') arch2=$value ;;
esac
done < <( VBoxManage list vms )
echo $arch
echo $arch2
since regex has greedy and non-greedy modes, if you have multiple targets on the same line, it would not extract as you wish. Line:
"tom" is a cat, and "jerry" is a mouse.
Target:
tom
jerry
Command (greedy mode):
grep -oP '".*"' name
Command (non-greedy mode):
grep -oP '".*?"' name
echo "\"tom\" is a cat, and \"jerry\" is a mouse." | tee >(cut -d \" -f 2) >(cut -d \" -f 4) >/dev/null
Jun 17, 2023 at 0:11
Here, we are using capturing group:
$ grep -oP '"\K.*(?=")' somefile
arch
arch2
If you want to use ripgrep, then the syntax looks like:
$ rg '"(.*)"' somefile -r '$1'
arch
arch2
In addition to Tiina's answer, if you have multiple targets on the same line
In Tiina's context,If you want to use ripgrep then:
echo "\"tom\" is a cat, and \"jerry\" is a mouse." | rg '"(.*?)"' --only-matching --replace '$1'
If you do not have rigprep (In Tiina's context), then:
echo "\"tom\" is a cat, and \"jerry\" is a mouse." | pee 'cut -d \" -f 2' 'cut -d \" -f 4'
or,
echo "\"tom\" is a cat, and \"jerry\" is a mouse." | pee 'cut -d \" -f 2' 'cut -d \" -f 4' | paste -d' ' - -