bash script regex to get directory path up nth levels











up vote
14
down vote

favorite
2












I'm using PWD to get the present working directory. Is there a SED or regex that I can use to, say, get the full path two parents up?










share|improve this question


























    up vote
    14
    down vote

    favorite
    2












    I'm using PWD to get the present working directory. Is there a SED or regex that I can use to, say, get the full path two parents up?










    share|improve this question
























      up vote
      14
      down vote

      favorite
      2









      up vote
      14
      down vote

      favorite
      2






      2





      I'm using PWD to get the present working directory. Is there a SED or regex that I can use to, say, get the full path two parents up?










      share|improve this question













      I'm using PWD to get the present working directory. Is there a SED or regex that I can use to, say, get the full path two parents up?







      regex bash sed






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Sep 24 '10 at 18:59









      Steve

      131138




      131138
























          5 Answers
          5






          active

          oldest

          votes

















          up vote
          15
          down vote



          accepted










          Why sed or regex? Why not dirname:



          parent=`dirname $PWD`
          grandparent=`dirname $parent`


          Edit:



          @Daentyh points out in the comments that apparently $() is preferred over backquotes `` for command substitution in POSIX-compliant shells. I don't have experience with them. More info:



          http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



          So, if this applies to your shell, you can (should?) use:



          parent=$(dirname $PWD)
          grandparent=$(dirname $parent)





          share|improve this answer























          • Thanks that worked!
            – Steve
            Sep 24 '10 at 19:15






          • 3




            You should use $() over `` since he specified bash.
            – Daenyth
            Sep 24 '10 at 19:17






          • 2




            Even so, $() is still POSIX sh. (Not all sh are POSIX though)
            – Daenyth
            Sep 24 '10 at 19:37






          • 2




            Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
            – Daenyth
            Sep 24 '10 at 19:52






          • 1




            Beware that grandparent of ./foo will be ..
            – Christoffer Hammarström
            Oct 1 '14 at 8:34


















          up vote
          17
          down vote













          This should work in POSIX shells:



          echo ${PWD%/*/*}


          which will give you an absolute path rather than a relative one.



          Also, see my answer here where I give two functions:



          cdn () { pushd .; for ((i=1; i<=$1; i++)); do cd ..; done; pwd; }


          which goes up n levels given n as an argument.



          And:



          cdu () { cd "${PWD%/$1/*}/$1"; }


          which goes up to a named subdirectory above the current working directory.






          share|improve this answer



















          • 2




            This should be the answer. This is more reusable than accepted answer.
            – melvynkim
            Feb 28 '14 at 23:25


















          up vote
          5
          down vote













          why not use



          "${PWD}/../.."


          ?






          share|improve this answer




























            up vote
            0
            down vote













            Not sed or regex, but this does do arbitrary parent quantity:



            $ cd $(mktemp -dp $(mktemp -dp $(mktemp -dp $(mktemp -d)))) && 
            > n=3 &&
            > readlink -f ${PWD}/$(for i in $(seq ${n}); do echo -n '../' ; done)
            /tmp/tmp.epGcUeLV9q


            In this example, I cd into a 5-deep temporary directory, assign n=3, construct a relative path n levels up from ${PWD}, and -f, --canonicalize the result with readlink.






            share|improve this answer




























              up vote
              0
              down vote













              Here's the regex that works for me. It's a little different between grep and Perl/sed:



              The extended regex breaks up paths into 0 or more groups of /ABC123 anchored to the end of line, essentially working backward. (.*) consumes everything prior to this match and replaces it.



              user@home:~/adir/bdir$ pwd
              /home/user/adir/bdir

              user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){0})$|1|'
              /home/user/adir/bdir

              user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){1})$|1|'
              /home/user/adir

              user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){2})$|1|'
              /home/user

              user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){3})$|1|'
              /home

              user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){4})$|1|'


              Grep can simulate substitution using a positive look ahead (?= which tells grep to match everything except the pattern. -Po tells grep to use Perl regex and show only the match.



              user@home:~/adir/bdir$ pwd
              /home/user/adir/bdir

              user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){0})$)'
              /home/user/adir/bdir

              user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){1})$)'
              /home/user/adir

              user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){2})$)'
              /home/user

              user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){3})$)'
              /home

              user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){4})$)'


              Of course it works equally well for Windows style paths:



              C:homeuseradirbdir> cd
              C:homeuseradirbdir

              C:homeuseradirbdir> cd | perl -pe 's|(.*)((\.*?){0})$|1|'
              C:homeuseradirbdir

              C:homeuseradirbdir> cd | sed -r 's|(.*)((\.*?){1})$|1|'
              C:homeuseradir

              C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){2})$)'
              C:homeuser

              C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){3})$)'
              C:home

              C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){4})$)'
              C:


              Sorry for the edits but I've been working on this enigma for about 16 hours now. Just kept trying different permutations and re-reading the regex docs. It had to sink in eventually.






              share|improve this answer























                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%2f3790101%2fbash-script-regex-to-get-directory-path-up-nth-levels%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                5 Answers
                5






                active

                oldest

                votes








                5 Answers
                5






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes








                up vote
                15
                down vote



                accepted










                Why sed or regex? Why not dirname:



                parent=`dirname $PWD`
                grandparent=`dirname $parent`


                Edit:



                @Daentyh points out in the comments that apparently $() is preferred over backquotes `` for command substitution in POSIX-compliant shells. I don't have experience with them. More info:



                http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



                So, if this applies to your shell, you can (should?) use:



                parent=$(dirname $PWD)
                grandparent=$(dirname $parent)





                share|improve this answer























                • Thanks that worked!
                  – Steve
                  Sep 24 '10 at 19:15






                • 3




                  You should use $() over `` since he specified bash.
                  – Daenyth
                  Sep 24 '10 at 19:17






                • 2




                  Even so, $() is still POSIX sh. (Not all sh are POSIX though)
                  – Daenyth
                  Sep 24 '10 at 19:37






                • 2




                  Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
                  – Daenyth
                  Sep 24 '10 at 19:52






                • 1




                  Beware that grandparent of ./foo will be ..
                  – Christoffer Hammarström
                  Oct 1 '14 at 8:34















                up vote
                15
                down vote



                accepted










                Why sed or regex? Why not dirname:



                parent=`dirname $PWD`
                grandparent=`dirname $parent`


                Edit:



                @Daentyh points out in the comments that apparently $() is preferred over backquotes `` for command substitution in POSIX-compliant shells. I don't have experience with them. More info:



                http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



                So, if this applies to your shell, you can (should?) use:



                parent=$(dirname $PWD)
                grandparent=$(dirname $parent)





                share|improve this answer























                • Thanks that worked!
                  – Steve
                  Sep 24 '10 at 19:15






                • 3




                  You should use $() over `` since he specified bash.
                  – Daenyth
                  Sep 24 '10 at 19:17






                • 2




                  Even so, $() is still POSIX sh. (Not all sh are POSIX though)
                  – Daenyth
                  Sep 24 '10 at 19:37






                • 2




                  Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
                  – Daenyth
                  Sep 24 '10 at 19:52






                • 1




                  Beware that grandparent of ./foo will be ..
                  – Christoffer Hammarström
                  Oct 1 '14 at 8:34













                up vote
                15
                down vote



                accepted







                up vote
                15
                down vote



                accepted






                Why sed or regex? Why not dirname:



                parent=`dirname $PWD`
                grandparent=`dirname $parent`


                Edit:



                @Daentyh points out in the comments that apparently $() is preferred over backquotes `` for command substitution in POSIX-compliant shells. I don't have experience with them. More info:



                http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



                So, if this applies to your shell, you can (should?) use:



                parent=$(dirname $PWD)
                grandparent=$(dirname $parent)





                share|improve this answer














                Why sed or regex? Why not dirname:



                parent=`dirname $PWD`
                grandparent=`dirname $parent`


                Edit:



                @Daentyh points out in the comments that apparently $() is preferred over backquotes `` for command substitution in POSIX-compliant shells. I don't have experience with them. More info:



                http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



                So, if this applies to your shell, you can (should?) use:



                parent=$(dirname $PWD)
                grandparent=$(dirname $parent)






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Sep 24 '10 at 19:49

























                answered Sep 24 '10 at 19:08









                Bert F

                62.6k1088118




                62.6k1088118












                • Thanks that worked!
                  – Steve
                  Sep 24 '10 at 19:15






                • 3




                  You should use $() over `` since he specified bash.
                  – Daenyth
                  Sep 24 '10 at 19:17






                • 2




                  Even so, $() is still POSIX sh. (Not all sh are POSIX though)
                  – Daenyth
                  Sep 24 '10 at 19:37






                • 2




                  Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
                  – Daenyth
                  Sep 24 '10 at 19:52






                • 1




                  Beware that grandparent of ./foo will be ..
                  – Christoffer Hammarström
                  Oct 1 '14 at 8:34


















                • Thanks that worked!
                  – Steve
                  Sep 24 '10 at 19:15






                • 3




                  You should use $() over `` since he specified bash.
                  – Daenyth
                  Sep 24 '10 at 19:17






                • 2




                  Even so, $() is still POSIX sh. (Not all sh are POSIX though)
                  – Daenyth
                  Sep 24 '10 at 19:37






                • 2




                  Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
                  – Daenyth
                  Sep 24 '10 at 19:52






                • 1




                  Beware that grandparent of ./foo will be ..
                  – Christoffer Hammarström
                  Oct 1 '14 at 8:34
















                Thanks that worked!
                – Steve
                Sep 24 '10 at 19:15




                Thanks that worked!
                – Steve
                Sep 24 '10 at 19:15




                3




                3




                You should use $() over `` since he specified bash.
                – Daenyth
                Sep 24 '10 at 19:17




                You should use $() over `` since he specified bash.
                – Daenyth
                Sep 24 '10 at 19:17




                2




                2




                Even so, $() is still POSIX sh. (Not all sh are POSIX though)
                – Daenyth
                Sep 24 '10 at 19:37




                Even so, $() is still POSIX sh. (Not all sh are POSIX though)
                – Daenyth
                Sep 24 '10 at 19:37




                2




                2




                Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
                – Daenyth
                Sep 24 '10 at 19:52




                Further nag: You should quote PWD as "$PWD", otherwise spaces in a directory name will break you. @Benoit's solution is far simpler though and will work anywhere without trouble. dirname is not entirely portable also.
                – Daenyth
                Sep 24 '10 at 19:52




                1




                1




                Beware that grandparent of ./foo will be ..
                – Christoffer Hammarström
                Oct 1 '14 at 8:34




                Beware that grandparent of ./foo will be ..
                – Christoffer Hammarström
                Oct 1 '14 at 8:34












                up vote
                17
                down vote













                This should work in POSIX shells:



                echo ${PWD%/*/*}


                which will give you an absolute path rather than a relative one.



                Also, see my answer here where I give two functions:



                cdn () { pushd .; for ((i=1; i<=$1; i++)); do cd ..; done; pwd; }


                which goes up n levels given n as an argument.



                And:



                cdu () { cd "${PWD%/$1/*}/$1"; }


                which goes up to a named subdirectory above the current working directory.






                share|improve this answer



















                • 2




                  This should be the answer. This is more reusable than accepted answer.
                  – melvynkim
                  Feb 28 '14 at 23:25















                up vote
                17
                down vote













                This should work in POSIX shells:



                echo ${PWD%/*/*}


                which will give you an absolute path rather than a relative one.



                Also, see my answer here where I give two functions:



                cdn () { pushd .; for ((i=1; i<=$1; i++)); do cd ..; done; pwd; }


                which goes up n levels given n as an argument.



                And:



                cdu () { cd "${PWD%/$1/*}/$1"; }


                which goes up to a named subdirectory above the current working directory.






                share|improve this answer



















                • 2




                  This should be the answer. This is more reusable than accepted answer.
                  – melvynkim
                  Feb 28 '14 at 23:25













                up vote
                17
                down vote










                up vote
                17
                down vote









                This should work in POSIX shells:



                echo ${PWD%/*/*}


                which will give you an absolute path rather than a relative one.



                Also, see my answer here where I give two functions:



                cdn () { pushd .; for ((i=1; i<=$1; i++)); do cd ..; done; pwd; }


                which goes up n levels given n as an argument.



                And:



                cdu () { cd "${PWD%/$1/*}/$1"; }


                which goes up to a named subdirectory above the current working directory.






                share|improve this answer














                This should work in POSIX shells:



                echo ${PWD%/*/*}


                which will give you an absolute path rather than a relative one.



                Also, see my answer here where I give two functions:



                cdn () { pushd .; for ((i=1; i<=$1; i++)); do cd ..; done; pwd; }


                which goes up n levels given n as an argument.



                And:



                cdu () { cd "${PWD%/$1/*}/$1"; }


                which goes up to a named subdirectory above the current working directory.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited Jul 16 at 13:04

























                answered Sep 24 '10 at 20:14









                Dennis Williamson

                234k63304368




                234k63304368








                • 2




                  This should be the answer. This is more reusable than accepted answer.
                  – melvynkim
                  Feb 28 '14 at 23:25














                • 2




                  This should be the answer. This is more reusable than accepted answer.
                  – melvynkim
                  Feb 28 '14 at 23:25








                2




                2




                This should be the answer. This is more reusable than accepted answer.
                – melvynkim
                Feb 28 '14 at 23:25




                This should be the answer. This is more reusable than accepted answer.
                – melvynkim
                Feb 28 '14 at 23:25










                up vote
                5
                down vote













                why not use



                "${PWD}/../.."


                ?






                share|improve this answer

























                  up vote
                  5
                  down vote













                  why not use



                  "${PWD}/../.."


                  ?






                  share|improve this answer























                    up vote
                    5
                    down vote










                    up vote
                    5
                    down vote









                    why not use



                    "${PWD}/../.."


                    ?






                    share|improve this answer












                    why not use



                    "${PWD}/../.."


                    ?







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Sep 24 '10 at 19:17









                    Benoit

                    58.3k13163211




                    58.3k13163211






















                        up vote
                        0
                        down vote













                        Not sed or regex, but this does do arbitrary parent quantity:



                        $ cd $(mktemp -dp $(mktemp -dp $(mktemp -dp $(mktemp -d)))) && 
                        > n=3 &&
                        > readlink -f ${PWD}/$(for i in $(seq ${n}); do echo -n '../' ; done)
                        /tmp/tmp.epGcUeLV9q


                        In this example, I cd into a 5-deep temporary directory, assign n=3, construct a relative path n levels up from ${PWD}, and -f, --canonicalize the result with readlink.






                        share|improve this answer

























                          up vote
                          0
                          down vote













                          Not sed or regex, but this does do arbitrary parent quantity:



                          $ cd $(mktemp -dp $(mktemp -dp $(mktemp -dp $(mktemp -d)))) && 
                          > n=3 &&
                          > readlink -f ${PWD}/$(for i in $(seq ${n}); do echo -n '../' ; done)
                          /tmp/tmp.epGcUeLV9q


                          In this example, I cd into a 5-deep temporary directory, assign n=3, construct a relative path n levels up from ${PWD}, and -f, --canonicalize the result with readlink.






                          share|improve this answer























                            up vote
                            0
                            down vote










                            up vote
                            0
                            down vote









                            Not sed or regex, but this does do arbitrary parent quantity:



                            $ cd $(mktemp -dp $(mktemp -dp $(mktemp -dp $(mktemp -d)))) && 
                            > n=3 &&
                            > readlink -f ${PWD}/$(for i in $(seq ${n}); do echo -n '../' ; done)
                            /tmp/tmp.epGcUeLV9q


                            In this example, I cd into a 5-deep temporary directory, assign n=3, construct a relative path n levels up from ${PWD}, and -f, --canonicalize the result with readlink.






                            share|improve this answer












                            Not sed or regex, but this does do arbitrary parent quantity:



                            $ cd $(mktemp -dp $(mktemp -dp $(mktemp -dp $(mktemp -d)))) && 
                            > n=3 &&
                            > readlink -f ${PWD}/$(for i in $(seq ${n}); do echo -n '../' ; done)
                            /tmp/tmp.epGcUeLV9q


                            In this example, I cd into a 5-deep temporary directory, assign n=3, construct a relative path n levels up from ${PWD}, and -f, --canonicalize the result with readlink.







                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Sep 23 '16 at 15:27









                            rubicks

                            2,2771722




                            2,2771722






















                                up vote
                                0
                                down vote













                                Here's the regex that works for me. It's a little different between grep and Perl/sed:



                                The extended regex breaks up paths into 0 or more groups of /ABC123 anchored to the end of line, essentially working backward. (.*) consumes everything prior to this match and replaces it.



                                user@home:~/adir/bdir$ pwd
                                /home/user/adir/bdir

                                user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){0})$|1|'
                                /home/user/adir/bdir

                                user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){1})$|1|'
                                /home/user/adir

                                user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){2})$|1|'
                                /home/user

                                user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){3})$|1|'
                                /home

                                user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){4})$|1|'


                                Grep can simulate substitution using a positive look ahead (?= which tells grep to match everything except the pattern. -Po tells grep to use Perl regex and show only the match.



                                user@home:~/adir/bdir$ pwd
                                /home/user/adir/bdir

                                user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){0})$)'
                                /home/user/adir/bdir

                                user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){1})$)'
                                /home/user/adir

                                user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){2})$)'
                                /home/user

                                user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){3})$)'
                                /home

                                user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){4})$)'


                                Of course it works equally well for Windows style paths:



                                C:homeuseradirbdir> cd
                                C:homeuseradirbdir

                                C:homeuseradirbdir> cd | perl -pe 's|(.*)((\.*?){0})$|1|'
                                C:homeuseradirbdir

                                C:homeuseradirbdir> cd | sed -r 's|(.*)((\.*?){1})$|1|'
                                C:homeuseradir

                                C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){2})$)'
                                C:homeuser

                                C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){3})$)'
                                C:home

                                C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){4})$)'
                                C:


                                Sorry for the edits but I've been working on this enigma for about 16 hours now. Just kept trying different permutations and re-reading the regex docs. It had to sink in eventually.






                                share|improve this answer



























                                  up vote
                                  0
                                  down vote













                                  Here's the regex that works for me. It's a little different between grep and Perl/sed:



                                  The extended regex breaks up paths into 0 or more groups of /ABC123 anchored to the end of line, essentially working backward. (.*) consumes everything prior to this match and replaces it.



                                  user@home:~/adir/bdir$ pwd
                                  /home/user/adir/bdir

                                  user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){0})$|1|'
                                  /home/user/adir/bdir

                                  user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){1})$|1|'
                                  /home/user/adir

                                  user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){2})$|1|'
                                  /home/user

                                  user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){3})$|1|'
                                  /home

                                  user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){4})$|1|'


                                  Grep can simulate substitution using a positive look ahead (?= which tells grep to match everything except the pattern. -Po tells grep to use Perl regex and show only the match.



                                  user@home:~/adir/bdir$ pwd
                                  /home/user/adir/bdir

                                  user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){0})$)'
                                  /home/user/adir/bdir

                                  user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){1})$)'
                                  /home/user/adir

                                  user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){2})$)'
                                  /home/user

                                  user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){3})$)'
                                  /home

                                  user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){4})$)'


                                  Of course it works equally well for Windows style paths:



                                  C:homeuseradirbdir> cd
                                  C:homeuseradirbdir

                                  C:homeuseradirbdir> cd | perl -pe 's|(.*)((\.*?){0})$|1|'
                                  C:homeuseradirbdir

                                  C:homeuseradirbdir> cd | sed -r 's|(.*)((\.*?){1})$|1|'
                                  C:homeuseradir

                                  C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){2})$)'
                                  C:homeuser

                                  C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){3})$)'
                                  C:home

                                  C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){4})$)'
                                  C:


                                  Sorry for the edits but I've been working on this enigma for about 16 hours now. Just kept trying different permutations and re-reading the regex docs. It had to sink in eventually.






                                  share|improve this answer

























                                    up vote
                                    0
                                    down vote










                                    up vote
                                    0
                                    down vote









                                    Here's the regex that works for me. It's a little different between grep and Perl/sed:



                                    The extended regex breaks up paths into 0 or more groups of /ABC123 anchored to the end of line, essentially working backward. (.*) consumes everything prior to this match and replaces it.



                                    user@home:~/adir/bdir$ pwd
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){0})$|1|'
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){1})$|1|'
                                    /home/user/adir

                                    user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){2})$|1|'
                                    /home/user

                                    user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){3})$|1|'
                                    /home

                                    user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){4})$|1|'


                                    Grep can simulate substitution using a positive look ahead (?= which tells grep to match everything except the pattern. -Po tells grep to use Perl regex and show only the match.



                                    user@home:~/adir/bdir$ pwd
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){0})$)'
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){1})$)'
                                    /home/user/adir

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){2})$)'
                                    /home/user

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){3})$)'
                                    /home

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){4})$)'


                                    Of course it works equally well for Windows style paths:



                                    C:homeuseradirbdir> cd
                                    C:homeuseradirbdir

                                    C:homeuseradirbdir> cd | perl -pe 's|(.*)((\.*?){0})$|1|'
                                    C:homeuseradirbdir

                                    C:homeuseradirbdir> cd | sed -r 's|(.*)((\.*?){1})$|1|'
                                    C:homeuseradir

                                    C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){2})$)'
                                    C:homeuser

                                    C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){3})$)'
                                    C:home

                                    C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){4})$)'
                                    C:


                                    Sorry for the edits but I've been working on this enigma for about 16 hours now. Just kept trying different permutations and re-reading the regex docs. It had to sink in eventually.






                                    share|improve this answer














                                    Here's the regex that works for me. It's a little different between grep and Perl/sed:



                                    The extended regex breaks up paths into 0 or more groups of /ABC123 anchored to the end of line, essentially working backward. (.*) consumes everything prior to this match and replaces it.



                                    user@home:~/adir/bdir$ pwd
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){0})$|1|'
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | perl -pe 's|(.*)((/.*?){1})$|1|'
                                    /home/user/adir

                                    user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){2})$|1|'
                                    /home/user

                                    user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){3})$|1|'
                                    /home

                                    user@home:~/adir/bdir$ pwd | sed -r 's|(.*)((/.*?){4})$|1|'


                                    Grep can simulate substitution using a positive look ahead (?= which tells grep to match everything except the pattern. -Po tells grep to use Perl regex and show only the match.



                                    user@home:~/adir/bdir$ pwd
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){0})$)'
                                    /home/user/adir/bdir

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){1})$)'
                                    /home/user/adir

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){2})$)'
                                    /home/user

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){3})$)'
                                    /home

                                    user@home:~/adir/bdir$ pwd | grep -Po '(.*)(?=((/.*?){4})$)'


                                    Of course it works equally well for Windows style paths:



                                    C:homeuseradirbdir> cd
                                    C:homeuseradirbdir

                                    C:homeuseradirbdir> cd | perl -pe 's|(.*)((\.*?){0})$|1|'
                                    C:homeuseradirbdir

                                    C:homeuseradirbdir> cd | sed -r 's|(.*)((\.*?){1})$|1|'
                                    C:homeuseradir

                                    C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){2})$)'
                                    C:homeuser

                                    C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){3})$)'
                                    C:home

                                    C:homeuseradirbdir> cd | grep -Po '(.*)(?=((\.*?){4})$)'
                                    C:


                                    Sorry for the edits but I've been working on this enigma for about 16 hours now. Just kept trying different permutations and re-reading the regex docs. It had to sink in eventually.







                                    share|improve this answer














                                    share|improve this answer



                                    share|improve this answer








                                    edited Nov 10 at 22:21

























                                    answered Nov 9 at 21:23









                                    noabody

                                    212




                                    212






























                                        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%2f3790101%2fbash-script-regex-to-get-directory-path-up-nth-levels%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

                                        Schultheiß

                                        Verwaltungsgliederung Dänemarks

                                        Liste der Kulturdenkmale in Wilsdruff