Follow

This one is super free! It is not a programming problem so much as a BASH problem.

Using bash parameter expansion only gnu.org/software/bash/manual/h

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) 

@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%/**/**/**}}

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) 

@Absinthe

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) 

@Absinthe

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?

Sign in to participate in the conversation
CleverLibre Social

CleverLibre Social is an inclusive social instance for open discussion, learning, and community.
All cultures welcome.
Hate speech and harassment strictly forbidden.