bash script regex to get directory path up nth levels
up vote
14
down vote
favorite
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
add a comment |
up vote
14
down vote
favorite
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
add a comment |
up vote
14
down vote
favorite
up vote
14
down vote
favorite
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
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
regex bash sed
asked Sep 24 '10 at 18:59
Steve
131138
131138
add a comment |
add a comment |
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)
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
|
show 1 more comment
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.
2
This should be the answer. This is more reusable than accepted answer.
– melvynkim
Feb 28 '14 at 23:25
add a comment |
up vote
5
down vote
why not use
"${PWD}/../.."
?
add a comment |
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
.
add a comment |
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.
add a comment |
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)
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
|
show 1 more comment
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)
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
|
show 1 more comment
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)
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)
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
|
show 1 more comment
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
|
show 1 more comment
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.
2
This should be the answer. This is more reusable than accepted answer.
– melvynkim
Feb 28 '14 at 23:25
add a comment |
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.
2
This should be the answer. This is more reusable than accepted answer.
– melvynkim
Feb 28 '14 at 23:25
add a comment |
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.
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.
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
add a comment |
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
add a comment |
up vote
5
down vote
why not use
"${PWD}/../.."
?
add a comment |
up vote
5
down vote
why not use
"${PWD}/../.."
?
add a comment |
up vote
5
down vote
up vote
5
down vote
why not use
"${PWD}/../.."
?
why not use
"${PWD}/../.."
?
answered Sep 24 '10 at 19:17
Benoit
58.3k13163211
58.3k13163211
add a comment |
add a comment |
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
.
add a comment |
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
.
add a comment |
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
.
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
.
answered Sep 23 '16 at 15:27
rubicks
2,2771722
2,2771722
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
edited Nov 10 at 22:21
answered Nov 9 at 21:23
noabody
212
212
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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