Jaki jest najprostszy sposób usunięcia końcowego ukośnika z każdego parametru?

104

Jaki jest najprostszy sposób na usunięcie końcowego ukośnika z każdego parametru w tablicy „$ @”, aby rsyncskopiować katalogi według nazwy?

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

Tytuł został zmieniony w celu wyjaśnienia. Aby zrozumieć komentarze i odpowiedzieć na temat wielu końcowych ukośników, zobacz historię edycji.

sid_com
źródło
2
możliwy duplikat Usuń ukośnik z końca zmiennej
Warren Dew

Odpowiedzi:

165

Możesz skorzystać z ${parameter%word}rozszerzenia opisanego tutaj . Oto prosty skrypt testowy, który demonstruje zachowanie:

#!/bin/bash

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

echo ${@%/}
Sean Bright
źródło
35
+1: Aby być bardzo pedantycznym, usunie to pojedynczy ukośnik, a nie wszystkie końcowe ukośniki. Aby usunąć dowolną liczbę końcowych ukośników:shopt -s extglob; echo "${@%%+(/)}"
glenn jackman
24
Ostrzeżenie: możesz nie chcieć usuwać końcowych ukośników we wszystkich przypadkach. Jeśli jako argument podano "/", usunięcie końcowego ukośnika będzie miało ... niefortunne konsekwencje.
Gordon Davisson,
13
WSKAZÓWKA: Połącz tr -s /ze zmiennym wyrażeniem regularnym, aby usunąć powtarzające się ukośniki, a następnie usuń ukośnik końcowy. np.DIR=$(echo //some///badly/written///dir////// | tr -s /); DIR=${DIR%/}
Dave
1
Naprawdę? Po usłyszeniu monitu biegnij set -- one///// two// three four/; shopt -s extglob; echo "${@%%+(/)}"i powiedz mi, co widzisz
glenn jackman
1
@twalberg Doceniam „protipsy”, które nie są tylko alternatywnymi odpowiedziami na pytanie OP w komentarzach.
Kyle Strand
40

Zaakceptowana odpowiedź spowoduje przycięcie JEDNEGO końcowego ukośnika.

Jeden ze sposobów przycinania wielu końcowych ukośników jest taki:

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

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

echo $VALUE $TRIMMED

Które wyjścia:

/looks/like/a/path/// /looks/like/a/path
Chris Johnson
źródło
1
Nie zapomnij cytować swoich zmiennych, na wypadek gdyby zawierały spacje: TRIMMED=$(echo "$VALUE" | sed 's:/*$::')
tetsujin
1
Właściwie nie jest to konieczne wewnątrz $()konstrukcji. Jednak jest to również nieszkodliwe :), więc prawdopodobnie dobrym zwyczajem jest używanie podwójnych cudzysłowów, "$VALUE"aby nie musieć decydować, kiedy i kiedy nie używać cudzysłowów.
Chris Johnson,
Czy jest jakiś sposób na połączenie tego z wcześniejszym nagraniem? Chcę usunąć protokół i (jeśli jest obecny) końcowy ukośnik z adresu URL, ale echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)/*$|\1|'nie działa (ponieważ grupa przechwytywania pasuje również do końcowego ukośnika). Mogę to zrobić za pomocą dwóch poleceń: echo "https://www.example.com/foo/" | sed -e 's|https*://\(.*\)$|\1|' -e 's|/*$||'ale zastanawiałem się, czy można to zrobić jednym?
Adam
Ta odpowiedź działała lepiej dla mnie z bardzo dużym plikiem wejściowym. Prosty sed 's:/*$::' < in.txt > out.txtdziała w kilka sekund
MitchellK
22

To działa dla mnie: ${VAR%%+(/)}

Jak opisano tutaj http://wiki.bash-hackers.org/syntax/pattern

Może być konieczne ustawienie opcji powłoki extglob. Nie widzę tego włączonego, ale nadal działa

Ivan
źródło
2
Aby zapytać o ustawienie: shopt extglobbez opcji
glenn jackman
To jest język rozszerzonych wzorców i należy go ustawić extglob.
ingyhere
1
To nie działa na wbudowanym bash Mac OS X. Powyższe rozwiązanie Seana Brighta:${VAR%/}
Alec Jacobson
15

realpathrozwiązuje podaną ścieżkę. Między innymi usuwa również końcowe ukośniki. Użyj, -saby zapobiec następowaniu linków SIM

DIR=/tmp/a///
echo $(realpath -s $DIR)
# output: /tmp/a
czerny
źródło
1
Wymaga istnienia wszystkich węzłów w ścieżce z wyjątkiem ostatniego. Jeśli użytkownik wrzuci jakąś ścieżkę nieistnienia, realpathzakończy się niepowodzeniem.
Livy
2
@Livy realpath --canonicalize-missingdziała absolutnie poprawnie z każdą nieistniejącą częścią ścieżki
maoizm
a na niektórych platformach brakuje realpath :-(
Mark Ribau
8

FYI, dodałem te dwie funkcje do mojej .bash_profilena podstawie odpowiedzi znalezionych w SO. Jak powiedział Chris Johnson, wszystkie odpowiedzi za pomocą ${x%/}usuwają tylko jeden ukośnik, te funkcje zrobią to, co mówią, mam nadzieję, że będzie to przydatne.

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

force_trailing_slash() {
    echo "$(rem_trailing_slash "$1")/"
}
Jonathan H.
źródło
4

W zsh możesz użyć :amodyfikatora.

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

echo "${DIRECTORY:a}"

=> /some/path/name

Działa to tak, jak, realpathale nie kończy się niepowodzeniem w przypadku braku plików / katalogów jako argumentu.

Nicolai Fröhlich
źródło