This one is super free! It is not a programming problem so much as a BASH problem.
Using bash parameter expansion only https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
Given an arbitrarily long path, such as "/head/shoulders/knees/and/toes/eyes/ears/mouth" stored in a variable $TEMP construct a parameter expansion to render only the last two subdirectory and filename like "eyes/ears/mouth" such that you can simply offer the command "echo ${TEMP<stuff goes in here>}"
And yes I do know how much easier it is to do with grep, sed, python, perl, awk <insert your favorite alternate solution here> can do it better and easier. This is a real world problem, and someone on Reddit pointed me in the right direction.
Solution (with caveat)
@khird close but that one still has the leading / on the output. Also, I don't think you need **, * will be sufficient. You are close :)
Solution (with caveat)
For some reason I had the idea the spec wanted the leading slash. This gets it without, but has the same caveat as the above.
echo ${TEMP#${TEMP%%+([^/])/+([^/])/+([^/])}}
Solution (with caveat)
@khird
That gives the final path without any '/' at all ..
You were closer with the previous one
Solution (with caveat)
@Absinthe Given your example where $TEMP="/head/shoulders/knees/and/toes/eyes/ears/mouth", it returns exactly "eyes/ears/mouth". Do you have a test case where it doesn't work?
Solution (with caveat)
@khird I just typed this in and got this:
$ TEMP="/head/shoulders/knees/and/toes/eyes/ears/mouth"
$ echo ${TEMP#${TEMP%%+([^/])/+([^/])/+([^/])}}
eyes ears mouth
Solution (with caveat)
@Absinthe Perhaps you have a bug in your version of Bash? That statetment involves two parameter manipulations - the inner removing a suffix and the outer removing a prefix. Neither of them should perform a character-replacement to print ' ' instead of '/'.
It works perfectly in Bash 4.3.11.
Solution (with caveat)
@khird interestnig, it works at work, on 5.0.3 I will have to check the laptop again when I get home.
Consider this:
echo "${TEMP#${TEMP%/*/*/*}/}"
Solution (with caveat)
@khird so I tried it in a new terminal window and it works. I tried it in the previous window and it still does it without the /'s funny that, but meh, almost with I could do that on purpose. But, anyway it works. Well done!
Solution (with caveat)
@khird you know the name of the variable because you are working with it... I think the original problem was based on something like
for I in $(ls SOMETHING) ; do SOMETHING with ${I <stuf>)
I just stored a bunch of crap in the $TEMP variable to play with it and not make the problem too complex.
Solution (with caveat)
In that context, you know the name of the variable. A solution where you don't need to know the name of the variable would be more useful in other circumstances, however.
For example, let's say I am allowed to execute but not modify a script which reads the pattern from a file or environment variable or something. If the permissions of that file or variable are insufficiently restrictive, I can manipulate the effect of the script by overwriting that pattern with my own. But if the script is going to make multiple calls like do_something_with ${TEMP1<foo>}; do_something_with ${TEMP2<foo>}; then I would need a version of <foo> that is independent of the name of the variable.
Solution (with caveat)
@khird is that possible within the constraints?
Solution (with caveat)
@Absinthe
The following _technically_ satisfies your requirements; in that I only replace the stuff in brackets from your example and doesn't use anything but parameter expansion.
However, there's a serious limitation I haven't figured out how to work around - it relies on knowing the name of the variable $TEMP. As stated the problem permits this, but that means I can't save my answer in a variable and reuse it like echo ${TEMP1<foo>}; echo ${TEMP2<foo>} without modifying <foo> in between.
echo ${TEMP#${TEMP%/**/**/**}}