Regex: Grab second string between two single quotes

Viewed 213

Can I get a little help matching a string in the below text?


The default username and password is 'user' and 'ZWiliWH8E2mV'.


I'm trying to get the string between the second set of single quotes: ZWiliWH8E2mV. This string is randomly generated, and I can only rely on the formatting, and not the ZWiliWH8E2mV. After some googling, I can match it with grep:

cat file_name | grep -oP "(?<=').*?(?=')"

but it's the 3rd match, and I'm not sure how to get to it from there. I'm open to using other tools if they're better for what I'm trying to do, but I'm not very versed in them.

4 Answers

As you stated in the question states that you are trying to get the string between the second set of single quotes, you could match the first 3 single quotes and start the match after it until the occurrence of the fourth single quote.

The negated character class [^']+ matches any char except a single quote.

^(?:[^']+'){3}\K[^']+(?=')

Explanation

  • ^ Start of string
  • ?:[^']+'){3}' Match 3 times any char except ' then match '
  • \K Clear the match buffer (Forget what is matches until this point)
  • [^']+ Match 1+ times any char except ' (What you want to match)
  • (?=') Positive lookahead, assert what is directly to the right is a '

Regex demo | Bash demo

The updated code might look like

cat file_name | grep -oP "^(?:[^']+'){3}\K[^']+(?=')"

I'm trying to get the string between the second set of single quotes

Using awk, you can avoid regex:

s="The default username and password is 'user' and 'ZWiliWH8E2mV'."

awk -F "'" '{print $4}' <<< "$s"
ZWiliWH8E2mV

Here we are using ' as field delimiter and 4th field in awk will give us 2nd value wrapped inside single quotes.

You may grab the value between the last two single quotation marks using grep:

grep -oP ".*'\\K[^']+(?=')" file_name

See the online demo

The -o option outputs only matched substrings and P makes grep use PCRE regex engine.

PCRE regex details

  • .* - any 0 or more chars other than line break chars, as many as possible
  • ' - a ' char
  • \K - match reset operator that discards all text matched so far in the overall match memory buffer
  • [^']+ - one or more chars other than a ' char
  • (?=') - a positive lookahead that makes sure there is a ' char immidiately to the right of the current location.

If you have multiple single quoted fields:

$ s="'first' and 'second' and 'third' and 'fourth' and the rest"

You can use the following Perl one liner to get the nth field:

echo "$s" |
perl -lne 'while (/[\x27]([^\x27]*)[\x27]/g) {print $1 if ++$i==3}'

# third

So for your example, the password is the second quoted field:

echo "The default username and password is 'user' and 'ZWiliWH8E2mV'." |
perl -lne 'while (/[\x27]([^\x27]*)[\x27]/g) {print $1 if ++$i==2}'

Prints:

ZWiliWH8E2mV

You can also use gawk with FPAT set to the same regex to print the nth field:

s="'first' and 'second' and 'third' and 'fourth' and the rest"

echo "$s" |
gawk -v n=2 'BEGIN{FPAT="[\x27][^\x27]*[\x27]"} 
            { gsub(/[\x27]/,"",$n); print $n}'

# second

Or you can use a pipeline of two GNU sed commands with n being the line you print in the second sed:

echo "$s" |
gsed -E 's/[^\x27]*\x27([^\x27]*)\x27[^\x27]*/\1\n/g' | gsed -nE '4p'
# fourth

Note:

[\x27] is the hex character representation for '. Hex character representations are supported by most regex implementations but not all. POSIX sed for example is dodgy.

Related