Как проще всего убрать косую черту в конце каждого параметра?

98

Каков самый простой способ удалить завершающую косую черту из каждого параметра в массиве '$ @', чтобы rsyncкаталоги копировались по имени?

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

Название изменено для пояснения. Чтобы понять комментарии и ответить о нескольких завершающих косых чертах, просмотрите историю редактирования.

sid_com
источник
2
возможный дубликат удаления косой черты в конце переменной
Уоррен Дью

Ответы:

160

Вы можете использовать ${parameter%word}расширение, которое подробно описано здесь . Вот простой тестовый сценарий, демонстрирующий поведение:

#!/bin/bash

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

echo ${@%/}
Шон Брайт
источник
35
+1: Чтобы быть очень педантичным, удалит одну косую черту, а не все конечные косые черты. Чтобы удалить любое количество косых shopt -s extglob; echo "${@%%+(/)}"
черт
24
Предупреждение: возможно, вы не захотите удалять завершающие слэши во всех случаях. Если в качестве аргумента указан "/", удаление завершающей косой черты будет иметь ... печальные последствия.
Гордон Дэвиссон
13
ЗАЩИТА: комбинируйте tr -s /с переменным регулярным выражением, чтобы удалить повторяющиеся косые черты, а затем удалите конечную косую черту. напримерDIR=$(echo //some///badly/written///dir////// | tr -s /); DIR=${DIR%/}
Дэйв
1
В самом деле? В командной строке bash запустите set -- one///// two// three four/; shopt -s extglob; echo "${@%%+(/)}"и скажите мне, что вы видите
Гленн Джекман
1
@twalberg Я ценю "подсказки", которые не просто альтернативные ответы на вопрос OP в обсуждениях.
Кайл Стрэнд,
39

В принятом ответе будет обрезана ОДНА завершающая косая черта.

Один из способов обрезать несколько конечных косых черт выглядит следующим образом:

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

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

echo $VALUE $TRIMMED

Какие выходы:

/looks/like/a/path/// /looks/like/a/path
Крис Джонсон
источник
1
Не забудьте TRIMMED=$(echo "$VALUE" | sed 's:/*$::')
заключить
1
На самом деле внутри $()конструкции это не обязательно . Однако это также безвредно :) так что, вероятно, будет хорошей практикой использовать двойные кавычки, "$VALUE"чтобы вам не приходилось решать, когда использовать двойные кавычки, а когда нет.
Крис Джонсон
Можно ли совместить это с более ранним захватом? Я хочу удалить протокол и (если есть) конечную косую черту из URL-адреса, но echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)/*$|\1|'не работает (поскольку группа захвата также соответствует конечной косой черте, я думаю). Я могу сделать это двумя командами: echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)$|\1|' -e 's|/*$||'но интересно, можно ли это сделать с помощью одной?
Адам
Этот ответ сработал для меня лучше с очень большим входным файлом. Простой sed 's:/*$::' < in.txt > out.txtделает работу за секунды
MitchellK
22

Это работает для меня: ${VAR%%+(/)}

Как описано здесь http://wiki.bash-hackers.org/syntax/pattern

Может потребоваться установить параметр оболочки extglob. Я не вижу, чтобы он был включен для меня, но он все еще работает

Иван
источник
2
Чтобы запросить настройку: shopt extglobбез параметров
Гленн Джекман
Это расширенный язык шаблонов, который необходимо установить extglob.
ingyhere 06
1
Это не работает во встроенном bash Mac OS X. Решение Шона Брайта, приведенное выше:${VAR%/}
Алек Джейкобсон,
13

realpathразрешает заданный путь. Помимо прочего, он также удаляет завершающие слэши. Используйте -sдля предотвращения следующих симлинков

DIR=/tmp/a///
echo $(realpath -s $DIR)
# output: /tmp/a
Черни
источник
1
Он требует, чтобы все узлы в пути, кроме последнего, существовали. Если пользователь вводит какой-то несуществующий путь, realpathпроизойдет сбой.
Ливи
2
@Livy realpath --canonicalize-missingабсолютно корректно работает с любой несуществующей частью пути
маоизм 09
а на некоторых платформах отсутствует realpath :-(
Марк Рибау
8

К вашему сведению, я добавил эти две функции к себе .bash_profileна основе ответов, найденных на SO. Как сказал Крис Джонсон, все ответы с использованием ${x%/}удаляют только одну косую черту, эти функции будут делать то, что они говорят, надеюсь, это полезно.

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

force_trailing_slash() {
    echo "$(rem_trailing_slash "$1")/"
}
Джонатан Х
источник
4

В zsh вы можете использовать :aмодификатор.

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

echo "${DIRECTORY:a}"

=> /some/path/name

Это действует realpathкак аргумент, но не приводит к ошибке с отсутствующими файлами / каталогами.

Николай Фрёлих
источник