Який найпростіший спосіб видалити кінцеву скісну риску з кожного параметра?


97

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

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

Заголовок змінено для уточнення. Щоб зрозуміти коментарі та відповісти щодо кількох косих рисок, перегляньте історію редагування.


Відповіді:


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
Справді? За баш-підказкою запустите set -- one///// two// three four/; shopt -s extglob; echo "${@%%+(/)}"і скажіть мені, що ви бачите
glenn jackman

1
@twalberg Я ціную "протики", які не є просто альтернативними відповідями на запитання OP у коментарях.
Kyle Strand

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:/*$::')
tetsujin

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

21

Це працює для мене: ${VAR%%+(/)}

Як описано тут http://wiki.bash-hackers.org/syntax/pattern

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


2
Щоб запитати налаштування: shopt extglobбез опцій
glenn jackman

Це розширена мова шаблонів, і ви повинні встановити extglob.
ingyhere

1
Це не працює на вбудованій програмі Mac OS X bash. Рішення Шона Брайта вище робить:${VAR%/}
Алек Якобсон

13

realpathвирішує заданий шлях. Крім усього іншого, він також видаляє кінцеві похилі риси. Використовуйте -sдля запобігання наступним симлінкам

DIR=/tmp/a///
echo $(realpath -s $DIR)
# output: /tmp/a

1
Для цього потрібні всі вузли у шляху, крім останнього. Якщо користувач кине якийсь неіснуючий шлях, realpathзазнає невдачі.
Лівій

2
@Livy realpath --canonicalize-missingпрацює абсолютно коректно з будь-якою неіснуючою частиною шляху
maoizm

а realpath відсутній на деяких платформах :-(
Марк Рібау

8

FYI, я додав ці дві функції до своєї .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але не дає збоїв у відсутності файлів / каталогів як аргумент.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.