What is the simplest way to remove a trailing slash from each parameter?

138.8k views Asked by At

What is the simplest way to remove a trailing slash from each parameter in the '$@' array, so that rsync copies the directories by name?

rsync -a --exclude='*~' "$@" "$dir"

The title has been changed for clarification. To understand the comments and answer about multiple trailing slashes see the edit history.

10

There are 10 answers

15
Sean Bright On BEST ANSWER

You can use the ${parameter%word} expansion that is detailed here. Here is a simple test script that demonstrates the behavior:

#!/bin/bash

# Call this as:
#   ./test.sh one/ two/ three/ 
#
# Output:
#  one two three

echo ${@%/}
0
Xavier Prudent On

Not the most beautiful way, but quick and easy.

I just add a slash and remove all doubles. Assuming such a pattern will not be found elsewhere.

WORD="abc/"
WORD=$WORD'/'
WORD=`echo $WORD | sed s/'\/\/'/''/g`
echo $WORD
0
ardnew On

Taking note of a couple comments in the accepted answer:

  1. Replace all repeated slashes //[...] with a single slash / (per @Dave comment)
  2. Remove trailing slash unless it is also the leading slash (i.e., the root filepath /) (per @GordonDavisson comment)
trimSlash() { for s; do sed -E 's://*:/:g; s:(^/)?/*$:\1:' <<< "${s}"; done; }

Not as concise as the answers using parameter substitution, but I think its worth the diligence.

Some test cases:

$ trimSlash "/" "///" "a/" "a/a/" "a///a/" "a/a" "a///a" "a///" "/a/a/" "///a///"
/
/
a
a/a
a/a
a/a
a/a
a
/a/a
/a
4
Ivan On

This works for me: ${VAR%%+(/)}

As described here http://wiki.bash-hackers.org/syntax/pattern

May need to set the shell option extglob. I can't see it enabled for me but it still works

3
czerny On

realpath resolves given path. Among other things it also removes trailing slashes. Use -s to prevent following simlinks

DIR=/tmp/a///
echo $(realpath -s $DIR)
# output: /tmp/a
0
Jonathan H On

FYI, I added these two functions to my .bash_profile based on the answers found on SO. As Chris Johnson said, all answers using ${x%/} remove only one slash, these functions will do what they say, hope this is useful.

rem_trailing_slash() {
    echo "$1" | sed 's/\/*$//g'
}

force_trailing_slash() {
    echo "$(rem_trailing_slash "$1")/"
}
0
Darren Smith On

Approach I have used, when trimming directory arguments that are intended for rsync, here using dirname and basename to split the path and then recombining the parts without the trailing slash.

raw_dir=/a/b/c/
trim_dir=$(dirname "$raw_dir")"/"$(basename "$raw_dir")
0
KFL On

Completely POSIX compliant

# recursively remove trailing slashes
remove_slashes() {
    res="${1%/}"
    if [ "$1" = "$res" ]
    then echo "$res"
    else remove_slashes "$res"
    fi
}

# test:
remove_slashes a/b/
remove_slashes a/b////
remove_slashes ""
remove_slashes ///
remove_slashes ///a
0
Nicolai Fröhlich On

In zsh you can use the :a modifier.

export DIRECTORY='/some//path/name//'

echo "${DIRECTORY:a}"

=> /some/path/name

This acts like realpath but doesn't fail with missing files/directories as argument.

4
Chris Johnson On

The accepted answer will trim ONE trailing slash.

One way to trim multiple trailing slashes is like this:

VALUE=/looks/like/a/path///

TRIMMED=$(echo "$VALUE" | sed 's:/*$::')

echo "$VALUE" "$TRIMMED"

Which outputs:

/looks/like/a/path/// /looks/like/a/path