help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] basename for n levels


From: Greg Wooledge
Subject: Re: [Help-bash] basename for n levels
Date: Wed, 10 Jun 2015 10:20:20 -0400
User-agent: Mutt/1.4.2.3i

On Wed, Jun 10, 2015 at 08:33:07AM -0500, Peng Yu wrote:
> For example:
> 
> If the input string is a////b///c///d//e, and n=3, the output should be c/d/e.

I did not see an "n" in the version of the question that was written
on this mailing list.  What kind of problem is this?  This smells more
and more like stupid homework.  Stop writing quizzes for yourself and
solve REAL WORLD PROBLEMS only.  Bash is a horrible language for solving
masturbatory academic "problems".  It has 40 years of accumulated trickery
for handling real problems and ONLY real problems.  It has no sane tools
for robust general programming.

So I will just ignore the additional numeric parameter and take the
original problem as written HERE ON THE MAILING LIST (not on a bloody
web site).

That problem said:

  input = a/b/c/d/e
  output = d/e

You can add the additional numeric parameter yourself.

If you need to handle an input like a////b/c///d//e, run it through a
normalization step first.

To handle inputs with embedded newlines using the "read" approach
(Stephane's objection), you can add -d '' to the read options.  But then
you have a new problem: <<< adds a newline, which read used to strip
out, but no longer does because read is no longer using newline as
the terminator, thanks to the -d '' option.

So, the best fix for that is to scrap the <<< altogether.

dirname=$'a/b\nb/c/d/e'
IFS=/ read -r -d '' -a parts < <(printf %s\\0 "$dirname")
rest omitted

At this point, the parameter expansion variant doesn't look so bad.
It won't handle the "n is also an input" crap, but that's not MY
problem.

And now, a normalization for handling your a////b////c//d//e case
(which you'd also need if you're using the parameter expansion method):

shopt -s extglob
normal=${dirname//\/+(\/)/\/}

"However," says Eric, "this breaks inputs with the special legacy case
of a leading double slash!"

So we can test for that specially.  We'll set a flag, and remove one of
the slashes, and put it back later.  Putting it all together:


#!/usr/bin/env bash
shopt -s extglob
dirname="$1"

stupid_leading_double_slash=0
if [[ $dirname = //[!/]* ]]; then
  stupid_leading_double_slash=1
  dirname=${dirname#/}
fi

# Normalize by removing extra slashes.
normal=${dirname//\/+(\/)/\/}

# Do either a read-splitting or parameter expansion solution here.
# Let's use PE for now.  Screw that "n is a parameter" crap.
left=${normal%/*/*}
output=${normal#"$left"/}

# Now, if the output is an absolute path (has a leading slash), but our
# original input had a leading double slash, we need to prepend one extra
# slash.
if ((stupid_leading_double_slash)) && [[ $output = /* ]]; then
  output="/$output"
fi

# Finally:
printf %s\\n "$output"


There.  Does all of THAT satisfy the stupid homework question now?



reply via email to

[Prev in Thread] Current Thread [Next in Thread]