Capturing Groups From a Grep RegEx











up vote
292
down vote

favorite
86












I've got this little script in sh (Mac OSX 10.6) to look through an array of files. Google has stopped being helpful at this point:



files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done


So far (obviously, to you shell gurus) $name merely holds 0, 1 or 2, depending on if grep found that the filename matched the matter provided. What I'd like is to capture what's inside the parens ([a-z]+) and store that to a variable.



I'd like to use grep only, if possible. If not, please no Python or Perl, etc. sed or something like it – I'm new to shell and would like to attack this from the *nix purist angle.



Also, as a super-cool bonus, I'm curious as to how I can concatenate string in shell? Is the group I captured was the string "somename" stored in $name, and I wanted to add the string ".jpg" to the end of it, could I cat $name '.jpg'?



Please explain what's going on, if you've got the time.










share|improve this question




















  • 23




    Is grep really purer unix than sed?
    – martin clayton
    Dec 12 '09 at 1:05






  • 1




    Ah, didn't mean to suggest that. I was just hoping that a solution could be found using a tool I'm specifically trying to learn here. If it's not possible to solve using grep, then sed would be great, if it's possible to solve using sed.
    – Isaac
    Dec 12 '09 at 1:09






  • 2




    I should have put a :) on that btw ...
    – martin clayton
    Dec 12 '09 at 1:31










  • Psh, my brain is way too fried today haha.
    – Isaac
    Dec 12 '09 at 1:34






  • 2




    @martinclayton That'd be an interesting argument. I do really think sed, (or ed to be precise) would be older (and therefore purer? maybe?) unix because grep derives it's name from the ed expression g(lobal)/re(gular expression)/p(rint).
    – ffledgling
    Mar 5 '13 at 15:18

















up vote
292
down vote

favorite
86












I've got this little script in sh (Mac OSX 10.6) to look through an array of files. Google has stopped being helpful at this point:



files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done


So far (obviously, to you shell gurus) $name merely holds 0, 1 or 2, depending on if grep found that the filename matched the matter provided. What I'd like is to capture what's inside the parens ([a-z]+) and store that to a variable.



I'd like to use grep only, if possible. If not, please no Python or Perl, etc. sed or something like it – I'm new to shell and would like to attack this from the *nix purist angle.



Also, as a super-cool bonus, I'm curious as to how I can concatenate string in shell? Is the group I captured was the string "somename" stored in $name, and I wanted to add the string ".jpg" to the end of it, could I cat $name '.jpg'?



Please explain what's going on, if you've got the time.










share|improve this question




















  • 23




    Is grep really purer unix than sed?
    – martin clayton
    Dec 12 '09 at 1:05






  • 1




    Ah, didn't mean to suggest that. I was just hoping that a solution could be found using a tool I'm specifically trying to learn here. If it's not possible to solve using grep, then sed would be great, if it's possible to solve using sed.
    – Isaac
    Dec 12 '09 at 1:09






  • 2




    I should have put a :) on that btw ...
    – martin clayton
    Dec 12 '09 at 1:31










  • Psh, my brain is way too fried today haha.
    – Isaac
    Dec 12 '09 at 1:34






  • 2




    @martinclayton That'd be an interesting argument. I do really think sed, (or ed to be precise) would be older (and therefore purer? maybe?) unix because grep derives it's name from the ed expression g(lobal)/re(gular expression)/p(rint).
    – ffledgling
    Mar 5 '13 at 15:18















up vote
292
down vote

favorite
86









up vote
292
down vote

favorite
86






86





I've got this little script in sh (Mac OSX 10.6) to look through an array of files. Google has stopped being helpful at this point:



files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done


So far (obviously, to you shell gurus) $name merely holds 0, 1 or 2, depending on if grep found that the filename matched the matter provided. What I'd like is to capture what's inside the parens ([a-z]+) and store that to a variable.



I'd like to use grep only, if possible. If not, please no Python or Perl, etc. sed or something like it – I'm new to shell and would like to attack this from the *nix purist angle.



Also, as a super-cool bonus, I'm curious as to how I can concatenate string in shell? Is the group I captured was the string "somename" stored in $name, and I wanted to add the string ".jpg" to the end of it, could I cat $name '.jpg'?



Please explain what's going on, if you've got the time.










share|improve this question















I've got this little script in sh (Mac OSX 10.6) to look through an array of files. Google has stopped being helpful at this point:



files="*.jpg"
for f in $files
do
echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?
echo $name
done


So far (obviously, to you shell gurus) $name merely holds 0, 1 or 2, depending on if grep found that the filename matched the matter provided. What I'd like is to capture what's inside the parens ([a-z]+) and store that to a variable.



I'd like to use grep only, if possible. If not, please no Python or Perl, etc. sed or something like it – I'm new to shell and would like to attack this from the *nix purist angle.



Also, as a super-cool bonus, I'm curious as to how I can concatenate string in shell? Is the group I captured was the string "somename" stored in $name, and I wanted to add the string ".jpg" to the end of it, could I cat $name '.jpg'?



Please explain what's going on, if you've got the time.







bash shell grep






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 1 '15 at 7:59









royhowie

8,891133658




8,891133658










asked Dec 12 '09 at 0:55









Isaac

9,20444569




9,20444569








  • 23




    Is grep really purer unix than sed?
    – martin clayton
    Dec 12 '09 at 1:05






  • 1




    Ah, didn't mean to suggest that. I was just hoping that a solution could be found using a tool I'm specifically trying to learn here. If it's not possible to solve using grep, then sed would be great, if it's possible to solve using sed.
    – Isaac
    Dec 12 '09 at 1:09






  • 2




    I should have put a :) on that btw ...
    – martin clayton
    Dec 12 '09 at 1:31










  • Psh, my brain is way too fried today haha.
    – Isaac
    Dec 12 '09 at 1:34






  • 2




    @martinclayton That'd be an interesting argument. I do really think sed, (or ed to be precise) would be older (and therefore purer? maybe?) unix because grep derives it's name from the ed expression g(lobal)/re(gular expression)/p(rint).
    – ffledgling
    Mar 5 '13 at 15:18
















  • 23




    Is grep really purer unix than sed?
    – martin clayton
    Dec 12 '09 at 1:05






  • 1




    Ah, didn't mean to suggest that. I was just hoping that a solution could be found using a tool I'm specifically trying to learn here. If it's not possible to solve using grep, then sed would be great, if it's possible to solve using sed.
    – Isaac
    Dec 12 '09 at 1:09






  • 2




    I should have put a :) on that btw ...
    – martin clayton
    Dec 12 '09 at 1:31










  • Psh, my brain is way too fried today haha.
    – Isaac
    Dec 12 '09 at 1:34






  • 2




    @martinclayton That'd be an interesting argument. I do really think sed, (or ed to be precise) would be older (and therefore purer? maybe?) unix because grep derives it's name from the ed expression g(lobal)/re(gular expression)/p(rint).
    – ffledgling
    Mar 5 '13 at 15:18










23




23




Is grep really purer unix than sed?
– martin clayton
Dec 12 '09 at 1:05




Is grep really purer unix than sed?
– martin clayton
Dec 12 '09 at 1:05




1




1




Ah, didn't mean to suggest that. I was just hoping that a solution could be found using a tool I'm specifically trying to learn here. If it's not possible to solve using grep, then sed would be great, if it's possible to solve using sed.
– Isaac
Dec 12 '09 at 1:09




Ah, didn't mean to suggest that. I was just hoping that a solution could be found using a tool I'm specifically trying to learn here. If it's not possible to solve using grep, then sed would be great, if it's possible to solve using sed.
– Isaac
Dec 12 '09 at 1:09




2




2




I should have put a :) on that btw ...
– martin clayton
Dec 12 '09 at 1:31




I should have put a :) on that btw ...
– martin clayton
Dec 12 '09 at 1:31












Psh, my brain is way too fried today haha.
– Isaac
Dec 12 '09 at 1:34




Psh, my brain is way too fried today haha.
– Isaac
Dec 12 '09 at 1:34




2




2




@martinclayton That'd be an interesting argument. I do really think sed, (or ed to be precise) would be older (and therefore purer? maybe?) unix because grep derives it's name from the ed expression g(lobal)/re(gular expression)/p(rint).
– ffledgling
Mar 5 '13 at 15:18






@martinclayton That'd be an interesting argument. I do really think sed, (or ed to be precise) would be older (and therefore purer? maybe?) unix because grep derives it's name from the ed expression g(lobal)/re(gular expression)/p(rint).
– ffledgling
Mar 5 '13 at 15:18














7 Answers
7






active

oldest

votes

















up vote
394
down vote



accepted










If you're using Bash, you don't even have to use grep:



files="*.jpg"
regex="[0-9]+_([a-z]+)_[0-9a-z]*"
for f in $files # unquoted in order to allow the glob to expand
do
if [[ $f =~ $regex ]]
then
name="${BASH_REMATCH[1]}"
echo "${name}.jpg" # concatenate strings
name="${name}.jpg" # same thing stored in a variable
else
echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
fi
done


It's better to put the regex in a variable. Some patterns won't work if included literally.



This uses =~ which is Bash's regex match operator. The results of the match are saved to an array called $BASH_REMATCH. The first capture group is stored in index 1, the second (if any) in index 2, etc. Index zero is the full match.



You should be aware that without anchors, this regex (and the one using grep) will match any of the following examples and more, which may not be what you're looking for:



123_abc_d4e5
xyz123_abc_d4e5
123_abc_d4e5.xyz
xyz123_abc_d4e5.xyz


To eliminate the second and fourth examples, make your regex like this:



^[0-9]+_([a-z]+)_[0-9a-z]*


which says the string must start with one or more digits. The carat represents the beginning of the string. If you add a dollar sign at the end of the regex, like this:



^[0-9]+_([a-z]+)_[0-9a-z]*$


then the third example will also be eliminated since the dot is not among the characters in the regex and the dollar sign represents the end of the string. Note that the fourth example fails this match as well.



If you have GNU grep (around 2.5 or later, I think, when the K operator was added):



name=$(echo "$f" | grep -Po '(?i)[0-9]+_K[a-z]+(?=_[0-9a-z]*)').jpg


The K operator (variable-length look-behind) causes the preceding pattern to match, but doesn't include the match in the result. The fixed-length equivalent is (?<=) - the pattern would be included before the closing parenthesis. You must use K if quantifiers may match strings of different lengths (e.g. +, *, {2,4}).



The (?=) operator matches fixed or variable-length patterns and is called "look-ahead". It also does not include the matched string in the result.



In order to make the match case-insensitive, the (?i) operator is used. It affects the patterns that follow it so its position is significant.



The regex might need to be adjusted depending on whether there are other characters in the filename. You'll note that in this case, I show an example of concatenating a string at the same time that the substring is captured.






share|improve this answer



















  • 30




    In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
    – Brandin
    Jan 9 '14 at 12:41












  • "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
    – Francesco Frassinelli
    Oct 12 '14 at 5:47






  • 2




    @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
    – Dennis Williamson
    Oct 12 '14 at 8:03






  • 4




    /K operator rocks.
    – razzak
    Dec 26 '14 at 21:11








  • 1




    @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
    – Dennis Williamson
    Mar 14 '16 at 20:12


















up vote
124
down vote













This isn't really possible with pure grep, at least not generally.



But if your pattern is suitable, you may be able to use grep multiple times within a pipeline to first reduce your line to a known format, and then to extract just the bit you want. (Although tools like cut and sed are far better at this).



Suppose for the sake of argument that your pattern was a bit simpler: [0-9]+_([a-z]+)_ You could extract this like so:



echo $name | grep -Ei '[0-9]+_[a-z]+_' | grep -oEi '[a-z]+'


The first grep would remove any lines that didn't match your overall patern, the second grep (which has --only-matching specified) would display the alpha portion of the name. This only works because the pattern is suitable: "alpha portion" is specific enough to pull out what you want.



(Aside: Personally I'd use grep + cut to achieve what you are after: echo $name | grep {pattern} | cut -d _ -f 2. This gets cut to parse the line into fields by splitting on the delimiter _, and returns just field 2 (field numbers start at 1)).



Unix philosophy is to have tools which do one thing, and do it well, and combine them to achieve non-trivial tasks, so I'd argue that grep + sed etc is a more Unixy way of doing things :-)






share|improve this answer

















  • 3




    for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
    – Isaac
    Dec 12 '09 at 1:43






  • 1




    using shell, no need for grep + cut. wasting overheads if OP has lots of files..
    – ghostdog74
    Dec 12 '09 at 4:10






  • 2




    i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
    – ghostdog74
    Dec 12 '09 at 4:43






  • 7




    @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
    – RobM
    Dec 13 '09 at 14:26










  • cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
    – ether_joe
    Oct 28 '14 at 23:00


















up vote
78
down vote













I realize that an answer was already accepted for this, but from a "strictly *nix purist angle" it seems like the right tool for the job is pcregrep, which doesn't seem to have been mentioned yet. Try changing the lines:



    echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
name=$?


to the following:



    name=$(echo $f | pcregrep -o1 -Ei '[0-9]+_([a-z]+)_[0-9a-z]*')


to get only the contents of the capturing group 1.



The pcregrep tool utilizes all of the same syntax you've already used with grep, but implements the functionality that you need.



The parameter -o works just like the grep version if it is bare, but it also accepts a numeric parameter in pcregrep, which indicates which capturing group you want to show.



With this solution there is a bare minimum of change required in the script. You simply replace one modular utility with another and tweak the parameters.



Interesting Note: You can use multiple -o arguments to return multiple capture groups in the order in which they appear on the line.






share|improve this answer

















  • 3




    pcregrep is not available by default in Mac OS X which is what the OP uses
    – grebneke
    Jan 1 '14 at 2:06






  • 1




    +1 for the one liner
    – Antoine Wils
    Jul 15 '14 at 13:11






  • 4




    My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
    – Peter Herdenborg
    Mar 25 '15 at 9:10






  • 2




    yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
    – zhuguowei
    Mar 17 '16 at 13:18






  • 2




    pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
    – Ville
    Feb 11 at 22:56




















up vote
22
down vote













Not possible in just grep I believe



for sed:



name=`echo $f | sed -E 's/([0-9]+_([a-z]+)_[0-9a-z]*)|.*/2/'`


I'll take a stab at the bonus though:



echo "$name.jpg"





share|improve this answer























  • Ah, of course, thanks for that haha.
    – Isaac
    Dec 12 '09 at 1:05






  • 2




    Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
    – Isaac
    Dec 12 '09 at 1:14










  • updated, will output a blank line if there isn't a match, so be sure to check for that
    – cobbal
    Dec 12 '09 at 1:19










  • It now outputs only blank lines!
    – Isaac
    Dec 12 '09 at 1:24










  • this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
    – ghostdog74
    Dec 12 '09 at 4:36


















up vote
12
down vote













This is a solution that uses gawk. It's something I find I need to use often so I created a function for it



function regex1 { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'1'}']}'; }


to use just do



$ echo 'hello world' | regex1 'hellos(.*)'
world





share|improve this answer




























    up vote
    2
    down vote













    A suggestion for you - you can use parameter expansion to remove the part of the name from the last underscore onwards, and similarly at the start:



    f=001_abc_0za.jpg
    work=${f%_*}
    name=${work#*_}


    Then name will have the value abc.



    See Apple developer docs, search forward for 'Parameter Expansion'.






    share|improve this answer

















    • 1




      Ah, now this does work. But is it unix-y enough? Hmm...
      – Isaac
      Dec 12 '09 at 1:42










    • this will not check for ([a-z]+).
      – ghostdog74
      Dec 12 '09 at 4:09










    • @levislevis - that's true, but, as commented by the OP, it does do what was needed.
      – martin clayton
      Dec 12 '09 at 5:18


















    up vote
    1
    down vote













    if you have bash, you can use extended globbing



    shopt -s extglob
    shopt -s nullglob
    shopt -s nocaseglob
    for file in +([0-9])_+([a-z])_+([a-z0-9]).jpg
    do
    IFS="_"
    set -- $file
    echo "This is your captured output : $2"
    done


    or



    ls +([0-9])_+([a-z])_+([a-z0-9]).jpg | while read file
    do
    IFS="_"
    set -- $file
    echo "This is your captured output : $2"
    done





    share|improve this answer























    • That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
      – Isaac
      Dec 12 '09 at 4:14










    • bash reference manual - 3.5.8.1 Pattern Matching
      – ghostdog74
      Dec 12 '09 at 4:27






    • 1




      forgot the link: here it is gnu.org/software/bash/manual/bashref.html
      – ghostdog74
      Dec 12 '09 at 4:31











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1891797%2fcapturing-groups-from-a-grep-regex%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    7 Answers
    7






    active

    oldest

    votes








    7 Answers
    7






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    394
    down vote



    accepted










    If you're using Bash, you don't even have to use grep:



    files="*.jpg"
    regex="[0-9]+_([a-z]+)_[0-9a-z]*"
    for f in $files # unquoted in order to allow the glob to expand
    do
    if [[ $f =~ $regex ]]
    then
    name="${BASH_REMATCH[1]}"
    echo "${name}.jpg" # concatenate strings
    name="${name}.jpg" # same thing stored in a variable
    else
    echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
    fi
    done


    It's better to put the regex in a variable. Some patterns won't work if included literally.



    This uses =~ which is Bash's regex match operator. The results of the match are saved to an array called $BASH_REMATCH. The first capture group is stored in index 1, the second (if any) in index 2, etc. Index zero is the full match.



    You should be aware that without anchors, this regex (and the one using grep) will match any of the following examples and more, which may not be what you're looking for:



    123_abc_d4e5
    xyz123_abc_d4e5
    123_abc_d4e5.xyz
    xyz123_abc_d4e5.xyz


    To eliminate the second and fourth examples, make your regex like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*


    which says the string must start with one or more digits. The carat represents the beginning of the string. If you add a dollar sign at the end of the regex, like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*$


    then the third example will also be eliminated since the dot is not among the characters in the regex and the dollar sign represents the end of the string. Note that the fourth example fails this match as well.



    If you have GNU grep (around 2.5 or later, I think, when the K operator was added):



    name=$(echo "$f" | grep -Po '(?i)[0-9]+_K[a-z]+(?=_[0-9a-z]*)').jpg


    The K operator (variable-length look-behind) causes the preceding pattern to match, but doesn't include the match in the result. The fixed-length equivalent is (?<=) - the pattern would be included before the closing parenthesis. You must use K if quantifiers may match strings of different lengths (e.g. +, *, {2,4}).



    The (?=) operator matches fixed or variable-length patterns and is called "look-ahead". It also does not include the matched string in the result.



    In order to make the match case-insensitive, the (?i) operator is used. It affects the patterns that follow it so its position is significant.



    The regex might need to be adjusted depending on whether there are other characters in the filename. You'll note that in this case, I show an example of concatenating a string at the same time that the substring is captured.






    share|improve this answer



















    • 30




      In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
      – Brandin
      Jan 9 '14 at 12:41












    • "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
      – Francesco Frassinelli
      Oct 12 '14 at 5:47






    • 2




      @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
      – Dennis Williamson
      Oct 12 '14 at 8:03






    • 4




      /K operator rocks.
      – razzak
      Dec 26 '14 at 21:11








    • 1




      @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
      – Dennis Williamson
      Mar 14 '16 at 20:12















    up vote
    394
    down vote



    accepted










    If you're using Bash, you don't even have to use grep:



    files="*.jpg"
    regex="[0-9]+_([a-z]+)_[0-9a-z]*"
    for f in $files # unquoted in order to allow the glob to expand
    do
    if [[ $f =~ $regex ]]
    then
    name="${BASH_REMATCH[1]}"
    echo "${name}.jpg" # concatenate strings
    name="${name}.jpg" # same thing stored in a variable
    else
    echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
    fi
    done


    It's better to put the regex in a variable. Some patterns won't work if included literally.



    This uses =~ which is Bash's regex match operator. The results of the match are saved to an array called $BASH_REMATCH. The first capture group is stored in index 1, the second (if any) in index 2, etc. Index zero is the full match.



    You should be aware that without anchors, this regex (and the one using grep) will match any of the following examples and more, which may not be what you're looking for:



    123_abc_d4e5
    xyz123_abc_d4e5
    123_abc_d4e5.xyz
    xyz123_abc_d4e5.xyz


    To eliminate the second and fourth examples, make your regex like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*


    which says the string must start with one or more digits. The carat represents the beginning of the string. If you add a dollar sign at the end of the regex, like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*$


    then the third example will also be eliminated since the dot is not among the characters in the regex and the dollar sign represents the end of the string. Note that the fourth example fails this match as well.



    If you have GNU grep (around 2.5 or later, I think, when the K operator was added):



    name=$(echo "$f" | grep -Po '(?i)[0-9]+_K[a-z]+(?=_[0-9a-z]*)').jpg


    The K operator (variable-length look-behind) causes the preceding pattern to match, but doesn't include the match in the result. The fixed-length equivalent is (?<=) - the pattern would be included before the closing parenthesis. You must use K if quantifiers may match strings of different lengths (e.g. +, *, {2,4}).



    The (?=) operator matches fixed or variable-length patterns and is called "look-ahead". It also does not include the matched string in the result.



    In order to make the match case-insensitive, the (?i) operator is used. It affects the patterns that follow it so its position is significant.



    The regex might need to be adjusted depending on whether there are other characters in the filename. You'll note that in this case, I show an example of concatenating a string at the same time that the substring is captured.






    share|improve this answer



















    • 30




      In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
      – Brandin
      Jan 9 '14 at 12:41












    • "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
      – Francesco Frassinelli
      Oct 12 '14 at 5:47






    • 2




      @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
      – Dennis Williamson
      Oct 12 '14 at 8:03






    • 4




      /K operator rocks.
      – razzak
      Dec 26 '14 at 21:11








    • 1




      @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
      – Dennis Williamson
      Mar 14 '16 at 20:12













    up vote
    394
    down vote



    accepted







    up vote
    394
    down vote



    accepted






    If you're using Bash, you don't even have to use grep:



    files="*.jpg"
    regex="[0-9]+_([a-z]+)_[0-9a-z]*"
    for f in $files # unquoted in order to allow the glob to expand
    do
    if [[ $f =~ $regex ]]
    then
    name="${BASH_REMATCH[1]}"
    echo "${name}.jpg" # concatenate strings
    name="${name}.jpg" # same thing stored in a variable
    else
    echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
    fi
    done


    It's better to put the regex in a variable. Some patterns won't work if included literally.



    This uses =~ which is Bash's regex match operator. The results of the match are saved to an array called $BASH_REMATCH. The first capture group is stored in index 1, the second (if any) in index 2, etc. Index zero is the full match.



    You should be aware that without anchors, this regex (and the one using grep) will match any of the following examples and more, which may not be what you're looking for:



    123_abc_d4e5
    xyz123_abc_d4e5
    123_abc_d4e5.xyz
    xyz123_abc_d4e5.xyz


    To eliminate the second and fourth examples, make your regex like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*


    which says the string must start with one or more digits. The carat represents the beginning of the string. If you add a dollar sign at the end of the regex, like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*$


    then the third example will also be eliminated since the dot is not among the characters in the regex and the dollar sign represents the end of the string. Note that the fourth example fails this match as well.



    If you have GNU grep (around 2.5 or later, I think, when the K operator was added):



    name=$(echo "$f" | grep -Po '(?i)[0-9]+_K[a-z]+(?=_[0-9a-z]*)').jpg


    The K operator (variable-length look-behind) causes the preceding pattern to match, but doesn't include the match in the result. The fixed-length equivalent is (?<=) - the pattern would be included before the closing parenthesis. You must use K if quantifiers may match strings of different lengths (e.g. +, *, {2,4}).



    The (?=) operator matches fixed or variable-length patterns and is called "look-ahead". It also does not include the matched string in the result.



    In order to make the match case-insensitive, the (?i) operator is used. It affects the patterns that follow it so its position is significant.



    The regex might need to be adjusted depending on whether there are other characters in the filename. You'll note that in this case, I show an example of concatenating a string at the same time that the substring is captured.






    share|improve this answer














    If you're using Bash, you don't even have to use grep:



    files="*.jpg"
    regex="[0-9]+_([a-z]+)_[0-9a-z]*"
    for f in $files # unquoted in order to allow the glob to expand
    do
    if [[ $f =~ $regex ]]
    then
    name="${BASH_REMATCH[1]}"
    echo "${name}.jpg" # concatenate strings
    name="${name}.jpg" # same thing stored in a variable
    else
    echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
    fi
    done


    It's better to put the regex in a variable. Some patterns won't work if included literally.



    This uses =~ which is Bash's regex match operator. The results of the match are saved to an array called $BASH_REMATCH. The first capture group is stored in index 1, the second (if any) in index 2, etc. Index zero is the full match.



    You should be aware that without anchors, this regex (and the one using grep) will match any of the following examples and more, which may not be what you're looking for:



    123_abc_d4e5
    xyz123_abc_d4e5
    123_abc_d4e5.xyz
    xyz123_abc_d4e5.xyz


    To eliminate the second and fourth examples, make your regex like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*


    which says the string must start with one or more digits. The carat represents the beginning of the string. If you add a dollar sign at the end of the regex, like this:



    ^[0-9]+_([a-z]+)_[0-9a-z]*$


    then the third example will also be eliminated since the dot is not among the characters in the regex and the dollar sign represents the end of the string. Note that the fourth example fails this match as well.



    If you have GNU grep (around 2.5 or later, I think, when the K operator was added):



    name=$(echo "$f" | grep -Po '(?i)[0-9]+_K[a-z]+(?=_[0-9a-z]*)').jpg


    The K operator (variable-length look-behind) causes the preceding pattern to match, but doesn't include the match in the result. The fixed-length equivalent is (?<=) - the pattern would be included before the closing parenthesis. You must use K if quantifiers may match strings of different lengths (e.g. +, *, {2,4}).



    The (?=) operator matches fixed or variable-length patterns and is called "look-ahead". It also does not include the matched string in the result.



    In order to make the match case-insensitive, the (?i) operator is used. It affects the patterns that follow it so its position is significant.



    The regex might need to be adjusted depending on whether there are other characters in the filename. You'll note that in this case, I show an example of concatenating a string at the same time that the substring is captured.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 22 at 14:01

























    answered Dec 12 '09 at 2:59









    Dennis Williamson

    235k63304368




    235k63304368








    • 30




      In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
      – Brandin
      Jan 9 '14 at 12:41












    • "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
      – Francesco Frassinelli
      Oct 12 '14 at 5:47






    • 2




      @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
      – Dennis Williamson
      Oct 12 '14 at 8:03






    • 4




      /K operator rocks.
      – razzak
      Dec 26 '14 at 21:11








    • 1




      @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
      – Dennis Williamson
      Mar 14 '16 at 20:12














    • 30




      In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
      – Brandin
      Jan 9 '14 at 12:41












    • "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
      – Francesco Frassinelli
      Oct 12 '14 at 5:47






    • 2




      @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
      – Dennis Williamson
      Oct 12 '14 at 8:03






    • 4




      /K operator rocks.
      – razzak
      Dec 26 '14 at 21:11








    • 1




      @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
      – Dennis Williamson
      Mar 14 '16 at 20:12








    30




    30




    In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
    – Brandin
    Jan 9 '14 at 12:41






    In this answer I want to upvote the specific line that says "It's better to put the regex in a variable. Some patterns won't work if included literally."
    – Brandin
    Jan 9 '14 at 12:41














    "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
    – Francesco Frassinelli
    Oct 12 '14 at 5:47




    "It's better to put the regex in a variable. Some patterns won't work if included literally." - Why does it happens? Is there a way fix them?
    – Francesco Frassinelli
    Oct 12 '14 at 5:47




    2




    2




    @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
    – Dennis Williamson
    Oct 12 '14 at 8:03




    @FrancescoFrassinelli: An example is a pattern that includes white space. It's awkward to escape and you can't use quotes since that forces it from a regex to an ordinary string. The correct way to do it is to use a variable. Quotes can be used during the assignment making things much simpler.
    – Dennis Williamson
    Oct 12 '14 at 8:03




    4




    4




    /K operator rocks.
    – razzak
    Dec 26 '14 at 21:11






    /K operator rocks.
    – razzak
    Dec 26 '14 at 21:11






    1




    1




    @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
    – Dennis Williamson
    Mar 14 '16 at 20:12




    @Brandon: It does work. What version of Bash are you using? Show me what you're doing that doesn't work and perhaps I can tell you why.
    – Dennis Williamson
    Mar 14 '16 at 20:12












    up vote
    124
    down vote













    This isn't really possible with pure grep, at least not generally.



    But if your pattern is suitable, you may be able to use grep multiple times within a pipeline to first reduce your line to a known format, and then to extract just the bit you want. (Although tools like cut and sed are far better at this).



    Suppose for the sake of argument that your pattern was a bit simpler: [0-9]+_([a-z]+)_ You could extract this like so:



    echo $name | grep -Ei '[0-9]+_[a-z]+_' | grep -oEi '[a-z]+'


    The first grep would remove any lines that didn't match your overall patern, the second grep (which has --only-matching specified) would display the alpha portion of the name. This only works because the pattern is suitable: "alpha portion" is specific enough to pull out what you want.



    (Aside: Personally I'd use grep + cut to achieve what you are after: echo $name | grep {pattern} | cut -d _ -f 2. This gets cut to parse the line into fields by splitting on the delimiter _, and returns just field 2 (field numbers start at 1)).



    Unix philosophy is to have tools which do one thing, and do it well, and combine them to achieve non-trivial tasks, so I'd argue that grep + sed etc is a more Unixy way of doing things :-)






    share|improve this answer

















    • 3




      for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
      – Isaac
      Dec 12 '09 at 1:43






    • 1




      using shell, no need for grep + cut. wasting overheads if OP has lots of files..
      – ghostdog74
      Dec 12 '09 at 4:10






    • 2




      i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
      – ghostdog74
      Dec 12 '09 at 4:43






    • 7




      @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
      – RobM
      Dec 13 '09 at 14:26










    • cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
      – ether_joe
      Oct 28 '14 at 23:00















    up vote
    124
    down vote













    This isn't really possible with pure grep, at least not generally.



    But if your pattern is suitable, you may be able to use grep multiple times within a pipeline to first reduce your line to a known format, and then to extract just the bit you want. (Although tools like cut and sed are far better at this).



    Suppose for the sake of argument that your pattern was a bit simpler: [0-9]+_([a-z]+)_ You could extract this like so:



    echo $name | grep -Ei '[0-9]+_[a-z]+_' | grep -oEi '[a-z]+'


    The first grep would remove any lines that didn't match your overall patern, the second grep (which has --only-matching specified) would display the alpha portion of the name. This only works because the pattern is suitable: "alpha portion" is specific enough to pull out what you want.



    (Aside: Personally I'd use grep + cut to achieve what you are after: echo $name | grep {pattern} | cut -d _ -f 2. This gets cut to parse the line into fields by splitting on the delimiter _, and returns just field 2 (field numbers start at 1)).



    Unix philosophy is to have tools which do one thing, and do it well, and combine them to achieve non-trivial tasks, so I'd argue that grep + sed etc is a more Unixy way of doing things :-)






    share|improve this answer

















    • 3




      for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
      – Isaac
      Dec 12 '09 at 1:43






    • 1




      using shell, no need for grep + cut. wasting overheads if OP has lots of files..
      – ghostdog74
      Dec 12 '09 at 4:10






    • 2




      i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
      – ghostdog74
      Dec 12 '09 at 4:43






    • 7




      @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
      – RobM
      Dec 13 '09 at 14:26










    • cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
      – ether_joe
      Oct 28 '14 at 23:00













    up vote
    124
    down vote










    up vote
    124
    down vote









    This isn't really possible with pure grep, at least not generally.



    But if your pattern is suitable, you may be able to use grep multiple times within a pipeline to first reduce your line to a known format, and then to extract just the bit you want. (Although tools like cut and sed are far better at this).



    Suppose for the sake of argument that your pattern was a bit simpler: [0-9]+_([a-z]+)_ You could extract this like so:



    echo $name | grep -Ei '[0-9]+_[a-z]+_' | grep -oEi '[a-z]+'


    The first grep would remove any lines that didn't match your overall patern, the second grep (which has --only-matching specified) would display the alpha portion of the name. This only works because the pattern is suitable: "alpha portion" is specific enough to pull out what you want.



    (Aside: Personally I'd use grep + cut to achieve what you are after: echo $name | grep {pattern} | cut -d _ -f 2. This gets cut to parse the line into fields by splitting on the delimiter _, and returns just field 2 (field numbers start at 1)).



    Unix philosophy is to have tools which do one thing, and do it well, and combine them to achieve non-trivial tasks, so I'd argue that grep + sed etc is a more Unixy way of doing things :-)






    share|improve this answer












    This isn't really possible with pure grep, at least not generally.



    But if your pattern is suitable, you may be able to use grep multiple times within a pipeline to first reduce your line to a known format, and then to extract just the bit you want. (Although tools like cut and sed are far better at this).



    Suppose for the sake of argument that your pattern was a bit simpler: [0-9]+_([a-z]+)_ You could extract this like so:



    echo $name | grep -Ei '[0-9]+_[a-z]+_' | grep -oEi '[a-z]+'


    The first grep would remove any lines that didn't match your overall patern, the second grep (which has --only-matching specified) would display the alpha portion of the name. This only works because the pattern is suitable: "alpha portion" is specific enough to pull out what you want.



    (Aside: Personally I'd use grep + cut to achieve what you are after: echo $name | grep {pattern} | cut -d _ -f 2. This gets cut to parse the line into fields by splitting on the delimiter _, and returns just field 2 (field numbers start at 1)).



    Unix philosophy is to have tools which do one thing, and do it well, and combine them to achieve non-trivial tasks, so I'd argue that grep + sed etc is a more Unixy way of doing things :-)







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Dec 12 '09 at 1:26









    RobM

    5,36923435




    5,36923435








    • 3




      for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
      – Isaac
      Dec 12 '09 at 1:43






    • 1




      using shell, no need for grep + cut. wasting overheads if OP has lots of files..
      – ghostdog74
      Dec 12 '09 at 4:10






    • 2




      i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
      – ghostdog74
      Dec 12 '09 at 4:43






    • 7




      @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
      – RobM
      Dec 13 '09 at 14:26










    • cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
      – ether_joe
      Oct 28 '14 at 23:00














    • 3




      for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
      – Isaac
      Dec 12 '09 at 1:43






    • 1




      using shell, no need for grep + cut. wasting overheads if OP has lots of files..
      – ghostdog74
      Dec 12 '09 at 4:10






    • 2




      i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
      – ghostdog74
      Dec 12 '09 at 4:43






    • 7




      @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
      – RobM
      Dec 13 '09 at 14:26










    • cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
      – ether_joe
      Oct 28 '14 at 23:00








    3




    3




    for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
    – Isaac
    Dec 12 '09 at 1:43




    for f in $files; do name=echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'| cut -d _ -f 2; Aha!
    – Isaac
    Dec 12 '09 at 1:43




    1




    1




    using shell, no need for grep + cut. wasting overheads if OP has lots of files..
    – ghostdog74
    Dec 12 '09 at 4:10




    using shell, no need for grep + cut. wasting overheads if OP has lots of files..
    – ghostdog74
    Dec 12 '09 at 4:10




    2




    2




    i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
    – ghostdog74
    Dec 12 '09 at 4:43




    i disagree with that "philosophy". if you can use the shell's in built capabilities without calling external commands, then your script will be a lot faster in performance. there are some tools that overlap in function. eg grep and sed and awk. all of them does string manipulations, but awk stands out above them all because it can do a lot more. Practically, all those chaining of commands, like the above double greps or grep+sed can be shortened by doing them with one awk process.
    – ghostdog74
    Dec 12 '09 at 4:43




    7




    7




    @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
    – RobM
    Dec 13 '09 at 14:26




    @ghostdog74: No argument here that chaining lots of tiny operations together is generally less efficient than doing it all in one place, but I stand by my assertion that the Unix philosophy is lots of tools working together. For instance, tar just archives files, it doesn't compress them, and because it outputs to STDOUT by default you can pipe it across the network with netcat, or compress it with bzip2, etc. Which to my mind reinforces the convention and general ethos that Unix tools should be able to work together in pipes.
    – RobM
    Dec 13 '09 at 14:26












    cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
    – ether_joe
    Oct 28 '14 at 23:00




    cut is awesome -- thanks for the tip! As for the tools vs efficiency argument, I like the simplicity of chaining tools.
    – ether_joe
    Oct 28 '14 at 23:00










    up vote
    78
    down vote













    I realize that an answer was already accepted for this, but from a "strictly *nix purist angle" it seems like the right tool for the job is pcregrep, which doesn't seem to have been mentioned yet. Try changing the lines:



        echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
    name=$?


    to the following:



        name=$(echo $f | pcregrep -o1 -Ei '[0-9]+_([a-z]+)_[0-9a-z]*')


    to get only the contents of the capturing group 1.



    The pcregrep tool utilizes all of the same syntax you've already used with grep, but implements the functionality that you need.



    The parameter -o works just like the grep version if it is bare, but it also accepts a numeric parameter in pcregrep, which indicates which capturing group you want to show.



    With this solution there is a bare minimum of change required in the script. You simply replace one modular utility with another and tweak the parameters.



    Interesting Note: You can use multiple -o arguments to return multiple capture groups in the order in which they appear on the line.






    share|improve this answer

















    • 3




      pcregrep is not available by default in Mac OS X which is what the OP uses
      – grebneke
      Jan 1 '14 at 2:06






    • 1




      +1 for the one liner
      – Antoine Wils
      Jul 15 '14 at 13:11






    • 4




      My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
      – Peter Herdenborg
      Mar 25 '15 at 9:10






    • 2




      yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
      – zhuguowei
      Mar 17 '16 at 13:18






    • 2




      pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
      – Ville
      Feb 11 at 22:56

















    up vote
    78
    down vote













    I realize that an answer was already accepted for this, but from a "strictly *nix purist angle" it seems like the right tool for the job is pcregrep, which doesn't seem to have been mentioned yet. Try changing the lines:



        echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
    name=$?


    to the following:



        name=$(echo $f | pcregrep -o1 -Ei '[0-9]+_([a-z]+)_[0-9a-z]*')


    to get only the contents of the capturing group 1.



    The pcregrep tool utilizes all of the same syntax you've already used with grep, but implements the functionality that you need.



    The parameter -o works just like the grep version if it is bare, but it also accepts a numeric parameter in pcregrep, which indicates which capturing group you want to show.



    With this solution there is a bare minimum of change required in the script. You simply replace one modular utility with another and tweak the parameters.



    Interesting Note: You can use multiple -o arguments to return multiple capture groups in the order in which they appear on the line.






    share|improve this answer

















    • 3




      pcregrep is not available by default in Mac OS X which is what the OP uses
      – grebneke
      Jan 1 '14 at 2:06






    • 1




      +1 for the one liner
      – Antoine Wils
      Jul 15 '14 at 13:11






    • 4




      My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
      – Peter Herdenborg
      Mar 25 '15 at 9:10






    • 2




      yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
      – zhuguowei
      Mar 17 '16 at 13:18






    • 2




      pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
      – Ville
      Feb 11 at 22:56















    up vote
    78
    down vote










    up vote
    78
    down vote









    I realize that an answer was already accepted for this, but from a "strictly *nix purist angle" it seems like the right tool for the job is pcregrep, which doesn't seem to have been mentioned yet. Try changing the lines:



        echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
    name=$?


    to the following:



        name=$(echo $f | pcregrep -o1 -Ei '[0-9]+_([a-z]+)_[0-9a-z]*')


    to get only the contents of the capturing group 1.



    The pcregrep tool utilizes all of the same syntax you've already used with grep, but implements the functionality that you need.



    The parameter -o works just like the grep version if it is bare, but it also accepts a numeric parameter in pcregrep, which indicates which capturing group you want to show.



    With this solution there is a bare minimum of change required in the script. You simply replace one modular utility with another and tweak the parameters.



    Interesting Note: You can use multiple -o arguments to return multiple capture groups in the order in which they appear on the line.






    share|improve this answer












    I realize that an answer was already accepted for this, but from a "strictly *nix purist angle" it seems like the right tool for the job is pcregrep, which doesn't seem to have been mentioned yet. Try changing the lines:



        echo $f | grep -oEi '[0-9]+_([a-z]+)_[0-9a-z]*'
    name=$?


    to the following:



        name=$(echo $f | pcregrep -o1 -Ei '[0-9]+_([a-z]+)_[0-9a-z]*')


    to get only the contents of the capturing group 1.



    The pcregrep tool utilizes all of the same syntax you've already used with grep, but implements the functionality that you need.



    The parameter -o works just like the grep version if it is bare, but it also accepts a numeric parameter in pcregrep, which indicates which capturing group you want to show.



    With this solution there is a bare minimum of change required in the script. You simply replace one modular utility with another and tweak the parameters.



    Interesting Note: You can use multiple -o arguments to return multiple capture groups in the order in which they appear on the line.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Mar 3 '13 at 17:14









    John Sherwood

    92964




    92964








    • 3




      pcregrep is not available by default in Mac OS X which is what the OP uses
      – grebneke
      Jan 1 '14 at 2:06






    • 1




      +1 for the one liner
      – Antoine Wils
      Jul 15 '14 at 13:11






    • 4




      My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
      – Peter Herdenborg
      Mar 25 '15 at 9:10






    • 2




      yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
      – zhuguowei
      Mar 17 '16 at 13:18






    • 2




      pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
      – Ville
      Feb 11 at 22:56
















    • 3




      pcregrep is not available by default in Mac OS X which is what the OP uses
      – grebneke
      Jan 1 '14 at 2:06






    • 1




      +1 for the one liner
      – Antoine Wils
      Jul 15 '14 at 13:11






    • 4




      My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
      – Peter Herdenborg
      Mar 25 '15 at 9:10






    • 2




      yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
      – zhuguowei
      Mar 17 '16 at 13:18






    • 2




      pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
      – Ville
      Feb 11 at 22:56










    3




    3




    pcregrep is not available by default in Mac OS X which is what the OP uses
    – grebneke
    Jan 1 '14 at 2:06




    pcregrep is not available by default in Mac OS X which is what the OP uses
    – grebneke
    Jan 1 '14 at 2:06




    1




    1




    +1 for the one liner
    – Antoine Wils
    Jul 15 '14 at 13:11




    +1 for the one liner
    – Antoine Wils
    Jul 15 '14 at 13:11




    4




    4




    My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
    – Peter Herdenborg
    Mar 25 '15 at 9:10




    My pcregrep doesn't seem to understand the digit after the -o: "Unknown option letter '1' in "-o1". Also no mention of that functionaliy when looking at pcregrep --help
    – Peter Herdenborg
    Mar 25 '15 at 9:10




    2




    2




    yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
    – zhuguowei
    Mar 17 '16 at 13:18




    yeah, very help, e.g. echo 'r123456 foo 2016-03-17' | pcregrep -o1 'r([0-9]+)' 123456
    – zhuguowei
    Mar 17 '16 at 13:18




    2




    2




    pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
    – Ville
    Feb 11 at 22:56






    pcregrep 8.41 (installed with apt-get install pcregrep on Ubuntu 16.03) doesn't recognize the -Ei switch. It works perfectly without it, though. On macOS, with pcregrep installed via homebrew (also 8.41) as @anishpatel mentions above, at least on High Sierra the -E switch is also not recognized.
    – Ville
    Feb 11 at 22:56












    up vote
    22
    down vote













    Not possible in just grep I believe



    for sed:



    name=`echo $f | sed -E 's/([0-9]+_([a-z]+)_[0-9a-z]*)|.*/2/'`


    I'll take a stab at the bonus though:



    echo "$name.jpg"





    share|improve this answer























    • Ah, of course, thanks for that haha.
      – Isaac
      Dec 12 '09 at 1:05






    • 2




      Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
      – Isaac
      Dec 12 '09 at 1:14










    • updated, will output a blank line if there isn't a match, so be sure to check for that
      – cobbal
      Dec 12 '09 at 1:19










    • It now outputs only blank lines!
      – Isaac
      Dec 12 '09 at 1:24










    • this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
      – ghostdog74
      Dec 12 '09 at 4:36















    up vote
    22
    down vote













    Not possible in just grep I believe



    for sed:



    name=`echo $f | sed -E 's/([0-9]+_([a-z]+)_[0-9a-z]*)|.*/2/'`


    I'll take a stab at the bonus though:



    echo "$name.jpg"





    share|improve this answer























    • Ah, of course, thanks for that haha.
      – Isaac
      Dec 12 '09 at 1:05






    • 2




      Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
      – Isaac
      Dec 12 '09 at 1:14










    • updated, will output a blank line if there isn't a match, so be sure to check for that
      – cobbal
      Dec 12 '09 at 1:19










    • It now outputs only blank lines!
      – Isaac
      Dec 12 '09 at 1:24










    • this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
      – ghostdog74
      Dec 12 '09 at 4:36













    up vote
    22
    down vote










    up vote
    22
    down vote









    Not possible in just grep I believe



    for sed:



    name=`echo $f | sed -E 's/([0-9]+_([a-z]+)_[0-9a-z]*)|.*/2/'`


    I'll take a stab at the bonus though:



    echo "$name.jpg"





    share|improve this answer














    Not possible in just grep I believe



    for sed:



    name=`echo $f | sed -E 's/([0-9]+_([a-z]+)_[0-9a-z]*)|.*/2/'`


    I'll take a stab at the bonus though:



    echo "$name.jpg"






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Dec 12 '09 at 1:17

























    answered Dec 12 '09 at 1:00









    cobbal

    58.6k14125148




    58.6k14125148












    • Ah, of course, thanks for that haha.
      – Isaac
      Dec 12 '09 at 1:05






    • 2




      Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
      – Isaac
      Dec 12 '09 at 1:14










    • updated, will output a blank line if there isn't a match, so be sure to check for that
      – cobbal
      Dec 12 '09 at 1:19










    • It now outputs only blank lines!
      – Isaac
      Dec 12 '09 at 1:24










    • this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
      – ghostdog74
      Dec 12 '09 at 4:36


















    • Ah, of course, thanks for that haha.
      – Isaac
      Dec 12 '09 at 1:05






    • 2




      Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
      – Isaac
      Dec 12 '09 at 1:14










    • updated, will output a blank line if there isn't a match, so be sure to check for that
      – cobbal
      Dec 12 '09 at 1:19










    • It now outputs only blank lines!
      – Isaac
      Dec 12 '09 at 1:24










    • this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
      – ghostdog74
      Dec 12 '09 at 4:36
















    Ah, of course, thanks for that haha.
    – Isaac
    Dec 12 '09 at 1:05




    Ah, of course, thanks for that haha.
    – Isaac
    Dec 12 '09 at 1:05




    2




    2




    Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
    – Isaac
    Dec 12 '09 at 1:14




    Unfortunately, that sed solution doesn't work. It simply prints out everything in my directory.
    – Isaac
    Dec 12 '09 at 1:14












    updated, will output a blank line if there isn't a match, so be sure to check for that
    – cobbal
    Dec 12 '09 at 1:19




    updated, will output a blank line if there isn't a match, so be sure to check for that
    – cobbal
    Dec 12 '09 at 1:19












    It now outputs only blank lines!
    – Isaac
    Dec 12 '09 at 1:24




    It now outputs only blank lines!
    – Isaac
    Dec 12 '09 at 1:24












    this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
    – ghostdog74
    Dec 12 '09 at 4:36




    this sed has a problem. The first group of capturing parenthesis encompass everything. Of course 2 will have nothing.
    – ghostdog74
    Dec 12 '09 at 4:36










    up vote
    12
    down vote













    This is a solution that uses gawk. It's something I find I need to use often so I created a function for it



    function regex1 { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'1'}']}'; }


    to use just do



    $ echo 'hello world' | regex1 'hellos(.*)'
    world





    share|improve this answer

























      up vote
      12
      down vote













      This is a solution that uses gawk. It's something I find I need to use often so I created a function for it



      function regex1 { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'1'}']}'; }


      to use just do



      $ echo 'hello world' | regex1 'hellos(.*)'
      world





      share|improve this answer























        up vote
        12
        down vote










        up vote
        12
        down vote









        This is a solution that uses gawk. It's something I find I need to use often so I created a function for it



        function regex1 { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'1'}']}'; }


        to use just do



        $ echo 'hello world' | regex1 'hellos(.*)'
        world





        share|improve this answer












        This is a solution that uses gawk. It's something I find I need to use often so I created a function for it



        function regex1 { gawk 'match($0,/'$1'/, ary) {print ary['${2:-'1'}']}'; }


        to use just do



        $ echo 'hello world' | regex1 'hellos(.*)'
        world






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jan 9 '13 at 6:37









        opsb

        17.4k177791




        17.4k177791






















            up vote
            2
            down vote













            A suggestion for you - you can use parameter expansion to remove the part of the name from the last underscore onwards, and similarly at the start:



            f=001_abc_0za.jpg
            work=${f%_*}
            name=${work#*_}


            Then name will have the value abc.



            See Apple developer docs, search forward for 'Parameter Expansion'.






            share|improve this answer

















            • 1




              Ah, now this does work. But is it unix-y enough? Hmm...
              – Isaac
              Dec 12 '09 at 1:42










            • this will not check for ([a-z]+).
              – ghostdog74
              Dec 12 '09 at 4:09










            • @levislevis - that's true, but, as commented by the OP, it does do what was needed.
              – martin clayton
              Dec 12 '09 at 5:18















            up vote
            2
            down vote













            A suggestion for you - you can use parameter expansion to remove the part of the name from the last underscore onwards, and similarly at the start:



            f=001_abc_0za.jpg
            work=${f%_*}
            name=${work#*_}


            Then name will have the value abc.



            See Apple developer docs, search forward for 'Parameter Expansion'.






            share|improve this answer

















            • 1




              Ah, now this does work. But is it unix-y enough? Hmm...
              – Isaac
              Dec 12 '09 at 1:42










            • this will not check for ([a-z]+).
              – ghostdog74
              Dec 12 '09 at 4:09










            • @levislevis - that's true, but, as commented by the OP, it does do what was needed.
              – martin clayton
              Dec 12 '09 at 5:18













            up vote
            2
            down vote










            up vote
            2
            down vote









            A suggestion for you - you can use parameter expansion to remove the part of the name from the last underscore onwards, and similarly at the start:



            f=001_abc_0za.jpg
            work=${f%_*}
            name=${work#*_}


            Then name will have the value abc.



            See Apple developer docs, search forward for 'Parameter Expansion'.






            share|improve this answer












            A suggestion for you - you can use parameter expansion to remove the part of the name from the last underscore onwards, and similarly at the start:



            f=001_abc_0za.jpg
            work=${f%_*}
            name=${work#*_}


            Then name will have the value abc.



            See Apple developer docs, search forward for 'Parameter Expansion'.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Dec 12 '09 at 1:16









            martin clayton

            65k17186179




            65k17186179








            • 1




              Ah, now this does work. But is it unix-y enough? Hmm...
              – Isaac
              Dec 12 '09 at 1:42










            • this will not check for ([a-z]+).
              – ghostdog74
              Dec 12 '09 at 4:09










            • @levislevis - that's true, but, as commented by the OP, it does do what was needed.
              – martin clayton
              Dec 12 '09 at 5:18














            • 1




              Ah, now this does work. But is it unix-y enough? Hmm...
              – Isaac
              Dec 12 '09 at 1:42










            • this will not check for ([a-z]+).
              – ghostdog74
              Dec 12 '09 at 4:09










            • @levislevis - that's true, but, as commented by the OP, it does do what was needed.
              – martin clayton
              Dec 12 '09 at 5:18








            1




            1




            Ah, now this does work. But is it unix-y enough? Hmm...
            – Isaac
            Dec 12 '09 at 1:42




            Ah, now this does work. But is it unix-y enough? Hmm...
            – Isaac
            Dec 12 '09 at 1:42












            this will not check for ([a-z]+).
            – ghostdog74
            Dec 12 '09 at 4:09




            this will not check for ([a-z]+).
            – ghostdog74
            Dec 12 '09 at 4:09












            @levislevis - that's true, but, as commented by the OP, it does do what was needed.
            – martin clayton
            Dec 12 '09 at 5:18




            @levislevis - that's true, but, as commented by the OP, it does do what was needed.
            – martin clayton
            Dec 12 '09 at 5:18










            up vote
            1
            down vote













            if you have bash, you can use extended globbing



            shopt -s extglob
            shopt -s nullglob
            shopt -s nocaseglob
            for file in +([0-9])_+([a-z])_+([a-z0-9]).jpg
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done


            or



            ls +([0-9])_+([a-z])_+([a-z0-9]).jpg | while read file
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done





            share|improve this answer























            • That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
              – Isaac
              Dec 12 '09 at 4:14










            • bash reference manual - 3.5.8.1 Pattern Matching
              – ghostdog74
              Dec 12 '09 at 4:27






            • 1




              forgot the link: here it is gnu.org/software/bash/manual/bashref.html
              – ghostdog74
              Dec 12 '09 at 4:31















            up vote
            1
            down vote













            if you have bash, you can use extended globbing



            shopt -s extglob
            shopt -s nullglob
            shopt -s nocaseglob
            for file in +([0-9])_+([a-z])_+([a-z0-9]).jpg
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done


            or



            ls +([0-9])_+([a-z])_+([a-z0-9]).jpg | while read file
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done





            share|improve this answer























            • That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
              – Isaac
              Dec 12 '09 at 4:14










            • bash reference manual - 3.5.8.1 Pattern Matching
              – ghostdog74
              Dec 12 '09 at 4:27






            • 1




              forgot the link: here it is gnu.org/software/bash/manual/bashref.html
              – ghostdog74
              Dec 12 '09 at 4:31













            up vote
            1
            down vote










            up vote
            1
            down vote









            if you have bash, you can use extended globbing



            shopt -s extglob
            shopt -s nullglob
            shopt -s nocaseglob
            for file in +([0-9])_+([a-z])_+([a-z0-9]).jpg
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done


            or



            ls +([0-9])_+([a-z])_+([a-z0-9]).jpg | while read file
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done





            share|improve this answer














            if you have bash, you can use extended globbing



            shopt -s extglob
            shopt -s nullglob
            shopt -s nocaseglob
            for file in +([0-9])_+([a-z])_+([a-z0-9]).jpg
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done


            or



            ls +([0-9])_+([a-z])_+([a-z0-9]).jpg | while read file
            do
            IFS="_"
            set -- $file
            echo "This is your captured output : $2"
            done






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 12 '09 at 4:12

























            answered Dec 12 '09 at 4:06









            ghostdog74

            214k39210296




            214k39210296












            • That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
              – Isaac
              Dec 12 '09 at 4:14










            • bash reference manual - 3.5.8.1 Pattern Matching
              – ghostdog74
              Dec 12 '09 at 4:27






            • 1




              forgot the link: here it is gnu.org/software/bash/manual/bashref.html
              – ghostdog74
              Dec 12 '09 at 4:31


















            • That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
              – Isaac
              Dec 12 '09 at 4:14










            • bash reference manual - 3.5.8.1 Pattern Matching
              – ghostdog74
              Dec 12 '09 at 4:27






            • 1




              forgot the link: here it is gnu.org/software/bash/manual/bashref.html
              – ghostdog74
              Dec 12 '09 at 4:31
















            That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
            – Isaac
            Dec 12 '09 at 4:14




            That looks intriguing. Could you perhaps append a little explanation to it? Or, if you're so inclined, link to a particularly insightful resource that explains it? Thanks!
            – Isaac
            Dec 12 '09 at 4:14












            bash reference manual - 3.5.8.1 Pattern Matching
            – ghostdog74
            Dec 12 '09 at 4:27




            bash reference manual - 3.5.8.1 Pattern Matching
            – ghostdog74
            Dec 12 '09 at 4:27




            1




            1




            forgot the link: here it is gnu.org/software/bash/manual/bashref.html
            – ghostdog74
            Dec 12 '09 at 4:31




            forgot the link: here it is gnu.org/software/bash/manual/bashref.html
            – ghostdog74
            Dec 12 '09 at 4:31


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f1891797%2fcapturing-groups-from-a-grep-regex%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            What visual should I use to simply compare current year value vs last year in Power BI desktop

            How to ignore python UserWarning in pytest?

            Alexandru Averescu