6

Say for example I have a path like

path_1=/this/is/a/path/with/slash/

How do I get the following:

/this/is/a/path/with/slash

so the path without the last "/"

4
  • 1
    Assuming the original path is valid (…/slash/ leads to a directory), if you want to postpend a component and you're not sure if $path_1 ends with /, don't bother and just postpend /component: …/slash//component will work like …/slash/component. There's at least one situation when the trailing slash matters though: if slash is a symlink to a directory then …/slash/ means the directory, certainly not the symlink, while …/slash may mean the symlink. Then your question is useful. Commented Jan 30, 2022 at 22:27
  • Isn't his a duplicate? I.e.: I cannot believe this hadn't be asked and answered several hundred times.
    – U. Windl
    Commented Feb 1, 2022 at 8:45
  • See stackoverflow.com/a/47592882/6607497 for example.
    – U. Windl
    Commented Feb 1, 2022 at 9:06
  • that answer is barely understandable. The replies to this question are much better. Commented Feb 2, 2022 at 2:07

5 Answers 5

29

All POSIX shells have (c.f. man bash) "Parameter Expansion: Remove matching suffix pattern". So, use

$ echo "${path_1%/}"
/this/is/a/path/with/slash

If the variable's value does not end in a slash, then the value would be outputted without modification.

1
  • 5
    This has one possible problem: if the path is just "/" (i.e. the filesystem root), you don't want to remove the / because it'll turn into the empty string, which means something entirely different. Commented Jan 31, 2022 at 16:41
11

You can use realpath

DIR=/tmp/foo///
echo "$(realpath -s "$DIR")"
# output: /tmp/foo
3

Another way of removing the slash is

 $ echo "$(dirname -- "$path")/$(basename -- "$path")"

We just combined the two common shell commands dirname and basename.

2
  • 3
    You need to quote the expansion of $path and also the command substitution itself to avoid the issues mentioned in When is double-quoting necessary?. (See also What's the right way to quote $(command $arg)?). Also if the filename can start with a dash, -- is needed so that it's not taken as a bunch of options. Of course this will also rewrite paths like foo/ into ./foo.
    – ilkkachu
    Commented Jan 30, 2022 at 19:27
  • 1
    It's unfortunate that you use path as the variable's name. In the bash shell, it doesn't matter, but the path array variable in the zsh shell is tied to the PATH variable and will contain the elements of the PATH variable's :-delimited values.
    – Kusalananda
    Commented Jan 30, 2022 at 21:32
2

You can use sed in a simple way like this:

$ echo $path_1|sed 's-/$--'
/this/is/a/path/with/slash

Explanation:

  • s: Substitute. The first - marks the end of the command.
  • /$: Search pattern. The $ means look at the end of the line.
  • There is nothing between the second and third -, meaning, "replace the ending / with nothing".
  • You can use any character instead of - the most common is /, but since we are looking for the / itself, it is easier to use some other character. If one really wants to use /, then it would need to be escaped like so:

$ echo $path_1|sed 's/\/$//'

1

There are several options. I usually canonicalise the path. When you canonicalise a path, you get the base path.

For example, if the path is a link to a folder, the canonical form will get the actual path. It will also remove all double-slashes, which although unusual, are allowed in Unix and Linux.

Suppose ~/lf is a link to ~/.hidden/food/limes/.

PATHNAME=~/lf//price/
CANONICAL_PATH="$( realpath --canonicalize-existing "${PATHNAME}" )"
echo "${CANONICAL_PATH}"

The result would be /home/kamil/.hidden/food/limes/price

This also works for files, block devices, etc., although of course they don't have a trailing slash. For example, on my system:

PATHNAME=/dev/disk/by-partlabel/Boot
CANONICAL_PATH="$( realpath --canonicalize-existing "${PATHNAME}" )"
echo "${CANONICAL_PATH}"

The result is /dev/nvme0n1p2

If you aren't sure that the path exists, you need to add some error-checking.

PATHNAME=~/lf//price/
CANONICAL_PATH="$( realpath --canonicalize-existing "${PATHNAME}" 2>/dev/null )"
if [[ -z ${CANONICAL_PATH} ]]
then
    echo "Path doesn't exist: ${PATHNAME}" >&2
else
   echo "Canonical path is ${CANONICAL_PATH}"
fi

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .