Solidne budowanie ścieżek

16

Powiedzmy, że mam kilka zmiennych w skrypcie powłoki (np. W Zsh):

FOLDER_1, FOLDER_2, etc.

Te zmienne odnoszą się do folderów pochodzących z /. Na przykład, jeśli mam ścieżkę/home/me/stuff/items

zmienne byłyby następujące:

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

Teraz powiedz, że chcę zbudować z powrotem odpowiednią ścieżkę, łącząc zmienne. Jednym z możliwych sposobów jest zbudowanie ścieżki w następujący sposób:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

Powiedzmy jednak, że niektóre zmienne FOLDER_imają ukośniki końcowe, podczas gdy inne nie (i nie wiemy, które) np

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

Moje pytanie brzmi: jak mogę solidnie zbudować ścieżkę? (np. unikanie podwójnych ukośników i dodawanie ich tam, gdzie powinny być).

Pomyślałem, że jednym ze sposobów jest dodanie /zawsze między parami zmiennych, a następnie usunięcie wszelkich duplikatów za pomocą sed, ale nie mogę sprawić, by działało (nie jestem pewien, czy /poprawnie obsługuję sed).

A także czy odkrywam koło ? (tj. czy jest już jakieś wbudowane narzędzie, które to robi?).

Na koniec, jeśli zmienne są w tablicy , np. FOLDERSCzy byłoby to możliwe bez zapętlania? (lub alternatywnie, zapętlając, ale nie wiedząc, ile FOLDERSich jest w tablicy).

Amelio Vazquez-Reina
źródło

Odpowiedzi:

12

Możesz użyć printfz tablicą:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

W %tym przypadku operator przycina tylne struny /. Stosując go parts[@], przycina każdy element tablicy osobno.

Kluczem do zrozumienia tej printfsztuczki jest ten fragment man 1 printf: „Łańcuch formatu jest ponownie wykorzystywany tak często, jak to konieczne, aby zaspokoić argumenty”.

janmoesen
źródło
Pojedyncza %metoda działa dla pojedynczego ukośnika wymienionego w queston. Aby zaspokoić, gdy występuje wiele ukośników, ${parts[@]%%/*}działa. Oto link do nieco więcej informacji na temat ukośnika: Co oznaczają podwójne ukośniki w ścieżce UNIX? Czy 'cd dir / subdir // valid ...
Peter.O
2
@fered: /*w tym przypadku nie oznacza zero lub więcej ukośników , ale ukośnik, po którym następuje dowolna liczba znaków. Oznacza to, że jeśli twoja ścieżka zaczyna się od ukośnika, wynikiem będzie pusty ciąg!
l0b0 25.10.11
Rozważałem na przykładzie, że będą tylko końcowe ukośniki. Jednak, aby dostosować się do możliwości wprowadzenia ukośnika (ów), extglobmożna użyć bash (z wyrażeniem regularnym) ... shopt -s extglob; ${parts[@]%%/+(/)}...
Peter.O
15

Prosta odpowiedź to przestać się martwić i pokochać wiele cięć. Wiele ukośników ma taki sam efekt jak pojedynczy ukośnik (z wyjątkiem tego, że ścieżka rozpoczynająca się od //ma inne znaczenie w kilku systemach; jedyne, jakie mogę wymienić, to warstwy emulacji unixa w systemie Windows). Jest to zgodne z projektem, a możliwość łączenia nazw plików bez obaw o wiele ukośników była główną częścią tej decyzji projektowej.

Aby połączyć elementy tablicy, w zsh możesz użyć j flagi rozwijania parametrów .

dir=${(j:/:)FOLDERS}

Możesz zgnieść duplikaty, gdy jesteś przy nim, ale to czysto kosmetyczne.

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

W ksh i bash możesz dołączyć do tablicy, używając pierwszego znaku $IFSjako separatora. Następnie możesz wycisnąć duplikaty ukośników. W bash musisz zrobić, shopt -s extglobaby włączyć globs ksh w ostatnim wierszu fragmentu poniżej.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}
Gilles „SO- przestań być zły”
źródło
3

Jak ci sednie działa? Spróbuj sed 's|/\+|/|g'po konkatenacji lub sed 's|/||g'wcześniej.

Kevin
źródło
1

bash 4wprowadzono rozszerzone globowanie, które umożliwia dopasowanie wyrażeń regularnych w podstawianiu parametrów ${var....}... Domyślnie jest wyłączone. Aby włączyć go dla skryptu, wystarczy ustawić opcję powłoki extglob ...

Zakładając, że $ dir ==/home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

Wynikowa wartość $ reż

/home/me/stuff/items  

Oto kilka przykładów z do-i-nie-s - Bash Extended Globbing

Peter.O
źródło