What is the simplest way to remove a trailing slash from each parameter?
Solution 1
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 ${@%/}
Solution 2
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
Solution 3
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
Solution 4
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
Solution 5
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")/"
}
sid_com
Updated on February 18, 2022Comments
-
sid_com over 2 years
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.
-
glenn jackman over 12 years+1: To be highly pedantic, that will remove a single slash, not all trailing slashes. To remove any number of trailing slashes:
shopt -s extglob; echo "${@%%+(/)}"
-
Gordon Davisson over 12 yearsWarning: you may not want to remove trailing slashes in all cases. If "/" is supplied as an argument, removing the trailing slash will have ...unfortunate consequences.
-
Dave over 9 yearsPROTIP: Combine
tr -s /
with variable regex to remove repeated slashes then remove trailing slash. e.g.DIR=$(echo //some///badly/written///dir////// | tr -s /); DIR=${DIR%/}
-
twalberg over 9 years@Dave Why spawn an external
tr
when it can be done entirely within the shell, as shown by @glennjackman above? Never mind that the OP didn't ask to have strings of/
characters squashed from earlier parts of the string... -
Dave over 9 years@twalberg tr removes ANY repeated slashes. glennjackman example only removes TRAILING slashes. Also, I'm not sure that it is POSIX compliant. My example is POSIX compliant and does more cleanup. It was just a related thought. Doesn't answer the OP question directly.
-
twalberg over 9 years@Dave Exactly. The OP did not ask to remove ANY repeated slashes. Just trailing ones...
-
Julian F. Weinert over 9 years@glennjackman looks nice, but doe not do ANYTHING.
string_in == string_out
-
glenn jackman over 9 yearsReally? At a bash prompt, run
set -- one///// two// three four/; shopt -s extglob; echo "${@%%+(/)}"
and tell me what you see -
glenn jackman over 9 yearsTo query a setting:
shopt extglob
with no options -
Kyle Strand over 9 years@twalberg I appreciate "protips" that aren't just alternative answers to OP's question in comment threads.
-
ingyhere over 8 yearsThis is Extended Pattern Language and you must set
extglob
. -
einpoklum almost 8 yearsI'd say a separate script is overkill, see @Ivan's answer.
-
Sean Bright almost 8 years@einpoklum, it's in a "separate script" so that OP (or anyone) can easily just copy/paste it to test locally.
-
Alec Jacobson over 7 yearsThis doesn't work on Mac OS X's builtin bash. The solution by Sean Bright above does:
${VAR%/}
-
tetsujin almost 7 yearsDon't forget to quote your variables, in case they contain whitespace:
TRIMMED=$(echo "$VALUE" | sed 's:/*$::')
-
Chris Johnson almost 7 yearsActually that isn't necessary inside the
$()
construct. However it is also harmless :) so it's probably a good practice to use double quotes like"$VALUE"
so you don't have to decide when to and when not to use the double quotes. -
Adam almost 7 yearsAny way to combine this with an earlier capture? I want to strip protocol and (if present) trailing slash from a URL but
echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)/*$|\1|'
doesn't work (since the capture group matches the trailing slash as well i guess). I can do it with two commands:echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)$|\1|' -e 's|/*$||'
but wondered if it could be done with one? -
David Tonhofer almost 7 yearsWorrying about whether "tr" is spawned as a subprocess indicates that shell is not the correct solution for a problem (unless one is answering a twisty question for the Computer Bowl). Reading clarity trumps everything in 2010+ (insofar as that can even be had in sh/bash, stuff's is badly entropic with backwards compatibility)
-
MitchellK about 5 yearsThis answer worked better for me with a very big input file. A simple
sed 's:/*$::' < in.txt > out.txt
does the job in seconds -
Livy almost 5 yearsIt requires all nodes in the path except for the last one to exist. If the user throws in some non-existence path,
realpath
shall fail. -
maoizm over 4 years@Livy
realpath --canonicalize-missing
works absolutely correctly with any non-existing part of path -
mivk over 3 yearsNice and simple, BUT BEWARE: it breaks on arguments containing spaces! (at least if used in the way the OP intended).
-
Mark Ribau over 3 yearsand realpath is missing on some platforms :-(
-
mendel over 3 yearsrtFolderin=$1 rtFolder=${$rtFolderin%%+(/)} does not work for shell argument