Jak sprawdzić, czy $ PWD jest podkatalogiem danej ścieżki


25

Np. Sprawdź, czy $PWDjest podkatalogiem / home. Innymi słowy, szukam operacji ciągu bash, aby sprawdzić, czy jeden ciąg zaczyna się od drugiego.

Odpowiedzi:


26

Jeśli chcesz niezawodnie przetestować, czy katalog jest podkatalogiem innego, potrzebujesz czegoś więcej niż tylko sprawdzania prefiksu łańcucha. Odpowiedź Gillesa szczegółowo opisuje, jak poprawnie wykonać ten test.

Ale jeśli chcesz prostego sprawdzania prefiksu łańcucha (być może już znormalizowałeś swoje ścieżki?), Jest to dobre:

test "${PWD##/home/}" != "${PWD}"

Jeśli $PWDzaczyna się od „/ home /”, jest usuwany z lewej strony, co oznacza, że ​​nie pasuje do prawej strony, więc „! =” Zwraca true.


1
+1 idealne i dla bardziej ogólnego przypadku: [ "${PWD##$VAR}" != "$PWD" ]A gdyby to był [kod-golf] ( stackoverflow.com/questions/tagged/code-golf) pytanie, pobiłbyś mnie o dwa znaki ;-) Także wygląda bardziej czytelny ...
Tobias Kienzler

FWIW, może to być również przydatne:${PWD/#$HOME/\~}
user1338062,

W porządku, ale co z PWD = "/ home /../ etc /"
Alexis Peters

1
@AlexisPeters: Masz rację: koncentrowałem się na części pytania dotyczącej „przedrostka łańcucha” i zredagowałem ją, aby było to bardziej jasne. Gilles ładnie opisał właściwy sposób sprawdzania podkatalogów.
Jander

1
Służy "${PWD%%/subdir*}"do wykrywania, czy użytkownik znajduje się obecnie w subdirlub w podkatalogu subdir, ponieważ %% przechwytuje od końca ciągu zamiast od początku. Powinno to być przydatne dla każdego, kto szuka więcej informacji na temat podstawiania parametrów: tldp.org/LDP/abs/html/parameter-substitution.html
George Pantazes

33

Aby sprawdzić, czy ciąg znaków jest prefiksem innego, w dowolnej powłoce w stylu Bourne'a:

case $PWD/ in
  /home/*) echo "home sweet home";;
  *) echo "away from home";;
esac

Ta sama zasada działa w przypadku testu przyrostka lub podciągu. Zauważ, że w casekonstrukcjach, w przeciwieństwie do nazw plików, *pasuje dowolny znak, w tym a /lub inicjał ..

W powłokach, które implementują [[ … ]]składnię (tj. Bash, ksh i zsh), można jej użyć do dopasowania łańcucha do wzorca. (Zauważ, że [polecenie może testować tylko ciągi pod kątem równości.)

if [[ $PWD/ = /home/* ]]; then 

Jeśli konkretnie testujesz, czy bieżący katalog znajduje się pod spodem /home, prosty test podciągów nie wystarczy, ze względu na dowiązania symboliczne.

Jeśli /homejest to własny system plików, sprawdź, czy bieżący katalog ( .) znajduje się w tym systemie plików.

if [ "$(df -P . | awk 'NR==2 {print $6}')" = "/home" ]; then
  echo 'The current directory is on the /home filesystem'
fi

Jeśli masz NetBSD, OpenBSD lub GNU (tj. Linux) readlink, możesz użyć readlink -fdo usunięcia dowiązań symbolicznych ze ścieżki.

case $(readlink -f .)/ in $(readlink -f /home)/*) 

W przeciwnym razie możesz użyć pwddo wyświetlenia bieżącego katalogu. Należy jednak uważać, aby nie używać wbudowanej powłoki, jeśli powłoka śledzi cdpolecenia i zachowuje nazwę użytą do uzyskania dostępu do katalogu, a nie jego „rzeczywistą” lokalizację.

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) 

+1 Dzięki za tę wyczerpującą odpowiedź. Pytając o to, nie brałem pod uwagę osobliwości linków i systemu plików, ale zdecydowanie warto wiedzieć
Tobias Kienzler

8

Wersja surowa:

[ ${PWD:0:6} = "/home/" ]

Ma tę wadę, że najpierw trzeba liczyć postacie i nie można go zastąpić /home/czymś ogólnym $1.

edit (dzięki @ Michael) za uogólnienie do porównania z $VARjednym, którego można użyć

[ "${PWD:0:${#VAR}}" = $VAR ]

4
${#var}jest długością $var, więc możesz ją uogólnić jako[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek

@Michael Mrozek ♦: Dzięki, działa idealnie :)
Tobias Kienzler

2

Nie rozumiem tego pytania zbyt dobrze, ale aby znaleźć rodzica $ PWD , zrób to dirname $PWD. Aby znaleźć rodzica rodzica, uruchom dirname $(dirname $PWD)itd.


To działałoby tylko, gdybym znał głębokość, w przeciwnym razie skończę /. Ok, mógłbym sprawdzić rekurencyjnie, ale czy nie jest coś łatwiejszego?
Tobias Kienzler,

1
@tob Gdybym tylko znał programowanie powłoki ;-)
tshepang


0

Hm, szkoda, że [nie ma opcji testowania STRING1 starts with STRING2warunku.

Możesz spróbować echo $PWD | grep '^$VAR', ale może zawieść w interesujący sposób, gdy VARzawiera specjalne symbole.

awk„s indexfunkcja powinna być w stanie wykonać trick. Ale wszystko to wydaje się po prostu zbyt ciężkie, aby można było tak łatwo przetestować.


[[wykonuje wyrażenie regularne, więc zaczynasz od [[$ PWD = ~ ^ \ / home \ /]]
teknopaul

0

Jeśli znaleziona część ścieżki zostanie znaleziona, „opróżniam” zmienną:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
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.