1

In my zsh script, I would like to find out, whether my working directory starts with /cygdrive/?/... or matches exactly /cygdrive/? (where the drive letter (?) can be any letter different from the letter c), and if it does, retrieve into two variables the /cygdrive/? part and the remaining /.... Example: If my working directory is /cygdrive/r/abc/xyz, I would like to have the variable head set to /cygdrive/r and the variable tail set to /abc/xyz. If PWD is just, say, /cygdrive/r, the variable tail should be empty.

I prefer a solution using zsh internal commands only, i.e. without the need of spawning a process.

I came up with the following solution, which does the job, but I don't like it:

if [[ $PWD == /cygdrive/[abd-z]* ]]
then
  local head=${PWD:0:11}
  local tail=${PWD#/cygdrive/?}
  ....
fi

In particular, I don't like the calculation of head, with the hardcoded value of 11, and I'm wondering whether there might perhaps be a completely different approach, which would be more elegant.

UPDATE: I am aware that my if condition would also be true, if PWD is, for instance, /cygdrive/foo, but for my application, I don't consider this a problem. Of course if you can suggest a better alternative for writing the condition, which exactly does what I want, I appreciate any comment.

closed as unclear what you're asking by Sparhawk, schily, Thomas, msp9011, αғsнιη Aug 14 '18 at 14:51

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • @Sparhawk and other closers. Please indicate what's "unclear" in that question so it can be clarified. – Stéphane Chazelas Aug 14 '18 at 14:55
5
if [[ $PWD =~ '^(/cygdrive/[abd-z])(.*)' ]]; then
  head=$match[1]
  tail=$match[2]
fi

Same with globs:

set -o extendedglob
if [[ $PWD = (#b)(/cygdrive/[abd-z])(*) ]]; then
  head=$match[1]
  tail=$match[2]
fi

Globs also have the advantage of using zsh's own pattern matching where d-z only matches on defghijklmnopqrstuvwxyz, while =~ would use your system's regexps where [d-z] may very well match on many more characters (like é or even sequences of characters like dzs in Hungarian locales). Doing a set -o rematchpcre would cause =~ to use PCRE which are more reasonable in that regard.

To not match on /cygdrive/foo:

if [[ $PWD =~ '^(/cygdrive/[abd-z])(/.*)?$' ]]; then
  head=$match[1]
  tail=$match[2]
fi

With globs:

set -o extendedglob
if [[ $PWD = (#b)(/cygdrive/[abd-z])(/*|) ]]; then
  head=$match[1]
  tail=$match[2]
fi
  • Great, but one question for clarification: In your solution using extended globs, shouldn't it be [[ $PWD == ... ]] instead of [[ $PWD = ... ]]. From my understanding, using == in a conditional, causes the right side to be interpreted as a filename generation pattern. – user1934428 Aug 13 '18 at 9:58
  • 1
    @user1934428, = and == are strictly equivalent and both do pattern matching. The only case where they are different is with bash version 2.02 (and that version only). See What is the difference between [[ $a == z* ]] and [ $a == z* ]? for details. – Stéphane Chazelas Aug 13 '18 at 10:24
  • Right you are! My memory was tricking me. I should have read the zsh man page, where it clearly says about = vs. ==: The two forms are exactly equivalent. – user1934428 Aug 13 '18 at 15:10
2

Since you already know how to fetch the suffix of your variable, you can remove it from the variable to have the prefix:

if [[ $PWD == /cygdrive/[abd-z] ]]
then
  local tail=${PWD#/cygdrive/?}
  local head=${PWD%%$tail}
  ....
fi

As for the condition, you can use regular expressions in Zsh:

if [[ $PWD =~ '^/cygdrive/[abd-z](/.*)?$' ]]
then
    tail=${PWD#/cygdrive/?}
    head=${PWD%%$tail}

    echo "head is $head"
    echo "tail is $tail"
else
    echo "no match"
fi

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