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).

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”.


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//\/+(\/)//}

3

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


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.