3

How do i extract only

http://www.youtube.com/watch?v=qdRaf3-OEh4

from a URL like

http://www.youtube.com/watch?v=qdRaf3-OEh4&playnext=1&list=PL4367CEDBC117AEC6&feature=results_main

I am only interested in the "v" parameter.

1
  • 2
    @ObsessiveSSOℲ This has answers specifically written for command-line use, and one has many votes and is accepted. This has been interpreted by the OP, answer authors, and other members of the community in a way that's on topic. To whoever close voted, I recommend soliciting community input on meta before closing such questions. For questions within the scope of Ask Ubuntu, OPs' choices to post them here rather than elsewhere should be respected except when our community is clearly poorly suited to answering. See blog.stackoverflow.com/2012/03/…. Dec 25, 2012 at 10:54

2 Answers 2

14

Update:

The better ones would be:

sed 's/^.\+\(\/\|\&\|\?\)v=\([^\&]*\).*/\2/'
awk 'match($0,/((\/|&|\?)v=)([^&]*)/,x){print x[3]}'
grep -Po '(?<=(\/|&|\?)v=)[^&]*'
# Saying match / or & then v=

RFC 3986 states:

   URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

   query         = *( pchar / "/" / "?" )
   fragment      = *( pchar / "/" / "?" )

   pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
   unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
   sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
                 / "*" / "+" / "," / ";" / "="
   …

So to be safe use:

 | sed 's/#.*//' | - to remove #fragment part

in front.

I.e.

| sed 's/#.*//' | grep -Po '(?<=(\/|&)v=)[^&]*'

SED (2):

echo 'http://www.youtube.com/watch?v=qdRaf3-OEh4&playnext=1&list=PL4367CEDBC117AEC6&feature=results_main' \
| sed 's/^.\+\Wv=\([^\&]*\).*/\1/'

Explanation:


's       
/…/…/    /THIS/WITH THIS/

'substitute/MATCH 0 or MORE THINGS and GROUP them in ()/WITH THIS/

+-------------------------- s    _s_ubsititute
|+------------------------- /    START MATCH
||                    +---- /    END MATCH
||                    | +-- \1   REPLACE WITH - \1==Group 1. Or FIRS low ().
||                    | | +- /   End of SUBSTITUTE
s/^.\+\Wv=\([^\&]*\).*/\1/'
  +++-+-+-+-+-----+-+------- ^        Match from beginning of line
   ++-+-+-+-+-----+-+------- .        Match any character
    +-+-+-+-+-----+-+------- \+       multiple times (grep (greedy +, * *? etc))
      +-+-+-+-----+-+------- \W       Non-word-character
        +-+-+-----+-+------- v=       Literally match "v="
          +-+-----+-+------- \(       Start MATCH GROUP
            +-----+-+------- [^\&]*   Match any character BUT & - as many as possible
                  +-+------- \)       End MATCH GROUP
                    +------- .*       Match anything; *As many times as possible 
                                      - aka to end of line; as there is no 

         [abc]  would match a OR b OR c
         [abc]* would match a AND/OR b AND/OR c - as many times as possible
         [^abc] would match anything BUT a,b or c

/\1/     Replace ENTIRE match with MATCH GROUP number 1.
         That would be - everything between \( and \) - which his anything but "&"
         after the literal string "v=" - which in turn has a non word letter in 
         front of it.

         That also means that no match means no substitution which ultimately result in 
         no change.

Result: qdRaf3-OEh4

Note: If no match entire string will be returned.


(G)AWK:

echo 'http://www.youtube.com/watch?v=qdRaf3-OEh4&playnext=1&list=PL4367CEDBC117AEC6&feature=results_main' \
| awk 'match($0,/(\Wv=)([^&]*)/,v){print v[2]}'

Result: qdRaf3-OEh4

Explanation:

In Awk match(string, regexp) is a function that searches for the longest, leftmost, match of regexp in string. Here I have used an extension that comes with Gawk. (see Awk, GAwk; MAwk etc.) that places the individual matches - that is: what is between parenthesis - in an array of matches.

The pattern is fairly like the Perl/Grep one below.


  +-------------------------------------- Built in function
  |    +--------------------------------- Entire input ($1 would have been filed 1)
  |    |                                  etc. (Using default delimiters " "*)
  |    |
  |    |
  |    |  (....)(....) ------------------ Places \Wv= in one group 1, and [^&]* group 2.
match($0, /(\Wv=)([^&]*)/, v){print v[2]}
                           |   |    | |
                           |   |    +-+---- Use "v" from /, v; v is a user defined name
                           |   |      +---- 2 specifies index in v, which is group from
                           |   |            what is between ()'s in /…/
                           |   |
                           |   +----------- Print is another built in function.
                           +--------------- Group name that one can use in print.
                              



GREP (Using Perl-compatible):

echo 'http://www.youtube.com/watch?v=qdRaf3-OEh4&playnext=1&list=PL4367CEDBC117AEC6&feature=results_main' | \
grep -Po '(?<=\Wv=)[^&]*'

Result: qdRaf3-OEh4

Explanation:


-P  Use Perl compatible
-o  Only print match of the expression.
    - That means: Of our pattern only print/return what it matches.
    If nothing matches; return nothing.

          +------- ^    Negate math to - do not match (ONLY as it is FIRST between [])
          |+------ &    A literal "&" character
          || 
(?<=\Wv=)[^&]*
|   | |  |  ||
|   | |  |  |+---- *     Greedy; as many times as possible.
|   | |  +--+----- []    Wild order/any order of what is inside []
|   | +----------- v=    Literal v=
|   +------------- \W    Non Word character
+----------------- (?<=  What follows should be (mediately) preceded by.
                    ?=Huh, <=left, = =Equals to

So: Match literal "v=" where "v" is preceded by an non-word-character. Then match
anything; as many times as possible until we are at end of line or we meet an "&".

As you can't have "&" in an URL between key/value pairs this should be OK.

1
  • What will happen if v is the second parameter preceded by &?
    – Hendré
    Dec 18, 2012 at 21:14
4
echo 'http://www.youtube.com/watch?v=qdRaf3-OEh4&playnext=1&list=PL4367CEDBC117AEC6&feature=results_main' | sed -e 's/&.*//' -e 's/.*watch?//'

will get you v=qdRaf3-OEh4.

1
  • This code-only answer would be more valuable with an explanation. Apr 26, 2020 at 10:19

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .