sid_com
sid_com

Reputation: 25117

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

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.

Upvotes: 169

Views: 149136

Answers (10)

KFL
KFL

Reputation: 17850

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

Upvotes: 1

Chris Johnson
Chris Johnson

Reputation: 21956

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

Upvotes: 65

Darren Smith
Darren Smith

Reputation: 2488

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")

Upvotes: 1

ardnew
ardnew

Reputation: 2086

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

Upvotes: 0

Xavier Prudent
Xavier Prudent

Reputation: 1712

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

Upvotes: -1

Jonathan H
Jonathan H

Reputation: 7943

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")/"
}

Upvotes: 11

czerny
czerny

Reputation: 16634

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

Upvotes: 40

Ivan
Ivan

Reputation: 401

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

Upvotes: 40

Nicolai Fr&#246;hlich
Nicolai Fr&#246;hlich

Reputation: 52483

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.

Upvotes: 6

Sean Bright
Sean Bright

Reputation: 120644

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

Upvotes: 267

Related Questions