I have a path like this C:\Users\Administrator\Desktop\Photos-or\3-PRO\3-1-CR\CR-RESTS\LES-COQS\1920x500 and I'd like a regex to match the grandparent folder which, in this case, is LES-COQS.

I've tried:

echo "C:\Users\Administrator\Desktop\Photos-or\3-PRO\3-1-CR\CR-RESTS\LES-COQS\1920x500" | grep -i "[a-zA-Z0-9-]*\\\[0-9a-z]*$"

Should I use a lookahead/lookbehind ? Or is there a simpler way ?


  • 4
    That doesn't look like a path. Path components are / separated on Unix. Assuming you mean a MS-DOS path, I don't see LESCOQS in it, only LES-COQS which would be the directory containing the 1920x500 file, not its grandparent by any meaning of grandparent. Also, it's not clear what you mean by matching here. What's the output you're expecting? – Stéphane Chazelas Dec 11 '20 at 8:05
  • @StéphaneChazelas I would assume that 1920x500 is itself a directory and thus a "parent" of some unspecified file. Louis, is that right? – TooTea Dec 11 '20 at 8:41
  • it's a windows path, and I need a pure regex solution. – Louis Dec 11 '20 at 13:49
  • @TooTea yes right, the 1920x500 is the parent of some file indeed. – Louis Dec 11 '20 at 16:55
  • wrt I need a pure regex solution - so this is homework, right? Otherwise you wouldn't use a regexp for this. – Ed Morton Dec 12 '20 at 23:54

There are many ways to extract the penultimate item from the path. Here are a few with a mix of solution approaches


echo "$p" | grep -oP '.*\\\K[^\\]*(?=\\[^\\]+)'     # PCRE
echo "$p" | sed 's!^.*\\\([^\\]*\)\\[^\\]*$!\1!'    # RE

echo "$p" | awk -F'\\' '{print $(NF-1)}'            # Awk

IFS='\\' ps=($p); echo "${ps[-2]}"                  # Shell (bash)
px="${p%\\*}"; echo "${px##*\\}"                    # Shell

The expressions are much harder to read due to each backslash in the Windows folder path having to be matched by a double backslash in each RE pattern. (In fact, I worked on a couple of these by replacing \ with / throughout.)


Assuming you want to output the second-last component of that MS-DOS-style path, you could do:

expr "\\$msdos_path" : '.*\\\(.*\)\\.*'

Which here would output LES-COQS.

  • $ echo "C:\Users\Administrator\Desktop\Photos-originals\3-PROFESSSIONELS\3-1-CHR\CHR-RESTAURANTS\LESFRANGINS\1920x500" | grep -i '(.*)\\.*' returns the whole string. This doesn't work. – Louis Dec 11 '20 at 16:57
  • 1
    @Louis, grep is the tool to print the lines that match a regexp (that's named after the g/re/p command in ed) while here you want to extract a part of a string (which as it it's a path could be made of several lines), and so expr is a better tool for the task. – Stéphane Chazelas Dec 11 '20 at 17:03

May be this will help you to get the expected result

# GNU bash, version 4.4.20
echo "C:\Users\Administrator\Desktop\Photos-or\3-PRO\3-1-CR\CR-RESTS\LES-COQS\1920x500" | rev | awk -F'\' '{ print $2 }' | rev

Output :


Tested on : https://rextester.com/l/bash_online_compiler


You can use sed with extended regular expression and the substitution command:

$ echo "C:\Users\Administrator\Desktop\Photos-or\3-PRO\3-1-CR\CR-RESTS\LES-COQS\1920x500" | sed -E 's/(.*\\)([^\\]+)(\\[^\\]+)/\2/'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.