Removing slashes in file path

So apparently we cannot respond to old threads, and that's a pity because I wanted to respond to the following thread:

In that thread, the user @learnbash posted a bash scripting problem they were facing:
(paraphrasing for brevity)

# current output
/usr/sbin/httpd

# desired outcome
usr sbin httpd

In short, @learnbash wanted to match-replace forward slashes with whitespace.
I was mildly disappointed by the answers provided, because the best answer was not provided.

One of the answers was very close, @briandanielz demonstrated that Bash does string manipulation.

var="/usr/sbin/httpd"
removing_slash="${var##*/}"

echo "$removing_slash"

output

httpd

Which is a clever answer, and demonstrates how shell commands like basename or dirname are sometimes redundant as the modern command shell can do those things directly.

Other answers involved using sed, awk, or tr which are fine answers, but non-optimal since they involve using pipes which invokes a sub-shell, and sub-shells are slow.

Here is the correct answer:

var="/usr/sbin/httpd"
echo ${var////' '}

output:

usr sbin httpd

Bash has built-in string replacement ${parameter/pattern/string}
From the manual

The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. The match is performed according to the rules described below (see Pattern Matching). If pattern begins with ‘/’, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with ‘#’, it must match at the beginning of the expanded value of parameter. If pattern begins with ‘%’, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If the nocasematch shell option (see the description of shopt in The Shopt Builtin) is enabled, the match is performed without regard to the case of alphabetic characters. If parameter is ‘@’ or ‘’, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with ‘@’ or ‘’, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

Hopefully this formatted text renders correctly, because that series of repetitive forward-slashes needs some explanation:

${var////' '}
         ^  ^      # pattern separators, confusingly they are forward-slashes
          ^         # If pattern begins with ‘/’, all matches of pattern are replaced with string.
           ^        # pattern, a literal forward slash character.
              ^^^ # replace string, quoted white-space (this could be unquoted)

And there you have it. Bash parameter expansion is the fastest possible solution, if performance is of any concern. Then again, using tr might be more straight forward for you, and that's perfectly fine.

Thanks for reading.

1 Like

check out basename

The external command basename gives only the last component, and can be efficiently replaced by
echo "${var##*/}"

But the requirement was to substitute all slashes by spaces.
And yes, the echo "${var//// }" is more efficient than the external command tr

AFAIR the quoting of the space was required in an older bash version.
I say "space" - "white-space" usually means a consecutive chain of "space tab newline". (I first met it in the K&R "The C Programming Language".)

It is not "a pity" you cannot reply directly to a closed topic, its a feature.

Just like any topic, you can open a new topic and reference any other topic you wish.

Simple and well designed.

Reference and create new content :slight_smile: