Як перевірити, чи $ PWD є підкаталогом заданого шляху


25

Наприклад, перевірте, чи $PWDце підкаталог / home. Іншими словами, я шукаю операцію bash string, щоб перевірити, чи починається одна рядок з іншої.

Відповіді:


26

Якщо ви хочете надійно перевірити, чи каталог є підкаталогом іншого, вам знадобиться більше, ніж просто перевірка строкових префіксів. Відповідь Жиля докладно описує, як правильно зробити цей тест.

Але якщо ви хочете просту перевірку префікса рядка (можливо, ви вже нормалізували свої шляхи?), Це хороший варіант:

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

Якщо $PWDпочинається з "/ home /", його знімають у лівій частині, а це означає, що він не збігається з правою стороною, тому "! =" Повертає true.


1
+1 ідеально, і для більш загального випадку: [ "${PWD##$VAR}" != "$PWD" ]І якби це був [код-гольф] ( stackoverflow.com/questions/tagged/code-golf)запитання, ти би побив мене двома знаками ;-) Також це виглядає читабельніше ...
Тобіас Кіенцлер

FWIW, це також може бути корисно:${PWD/#$HOME/\~}
user1338062

Гаразд, а як щодо PWD = "/ home /../ etc /"
Alexis Peters

1
@AlexisPeters: Ти маєш рацію: я зосереджувався на частині питання "строковий префікс", і я відредагував це, щоб зробити це більш зрозумілим. Gilles чудово висвітлив належний спосіб перевірки наявності підкаталогів.
Джандер

1
Використовуйте "${PWD%%/subdir*}"для виявлення, чи перебуває зараз користувач у subdirпідкаталозі або subdir, оскільки %% захоплює з кінця рядка замість початку. Це повинно бути корисним для всіх, хто шукає додаткову інформацію про заміну параметрів: tldp.org/LDP/abs/html/parameter-substitution.html
Джордж Пантазес

33

Щоб перевірити, чи рядок є префіксом іншого, в будь-якій оболонці в стилі Борна:

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

Цей же принцип працює і для тесту суфікса чи підрядки. Зауважте, що в caseконструкціях, на відміну від імен файлів, *відповідає будь-якому символу, включаючи a /або початковий ..

У оболонках, які реалізують [[ … ]]синтаксис (тобто bash, ksh та zsh), його можна використовувати для зіставлення рядка з шаблоном. (Зверніть увагу, що [команда може перевірити лише рядки на рівність.)

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

Якщо ви спеціально перевіряєте, чи не знаходиться поточний каталог під ним /home, простого тесту підрядки недостатньо через символічні посилання.

Якщо /homeє власною файловою системою, перевірте, чи є поточна директорія ( .) у цій файловій системі.

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

Якщо у вас є NetBSD, OpenBSD або GNU (тобто Linux) readlink, ви можете скористатися readlink -fсимволічними посиланнями з шляху.

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

В іншому випадку ви можете використовувати pwdдля показу поточного каталогу. Але ви повинні подбати про те, щоб не використовувати вбудовану оболонку, якщо ваша оболонка відслідковує cdкоманди та зберігає ім’я, яким ви користувалися для досягнення каталогу, а не його "фактичного" розташування.

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

+1 Дякую за цю вичерпну відповідь. Я не розглядав посилання та особливості файлової системи, коли запитував це, але це, безумовно, добре знати
Tobias Kienzler

8

Сира версія:

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

Недоліком є ​​те, що спочатку треба рахувати символи, і його не можна замінити /home/чимось загальним на зразок $1.

редагувати (дякую @Michael) за узагальнення для порівняння з $VARодним можна використовувати

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

4
${#var}- це довжина $var, тому ви можете узагальнити це як[ "${PWD:0:${#1}}" = "$1" ]
Майкл Мрозек

@Michael Mrozek ♦: Дякую, прекрасно працює :)
Тобіас Кіенцлер

2

Я не дуже добре розумію питання, але, щоб знайти батьківську програму $ PWD , зробіть dirname $PWD. Щоб знайти батьківського батька, запустіть dirname $(dirname $PWD)і так далі ...


Це спрацювало б лише якби я знав глибину, інакше закінчую /. Гаразд, я міг би перевірити рекурсивно, але чи немає чогось легшого?
Тобіас Кіенцлер

1
@tob Якби я знав програмування оболонок ;-)
tshepang


0

Гм, шкода, що [немає можливості перевірити STRING1 starts with STRING2стан.

Ви можете спробувати echo $PWD | grep '^$VAR', але це може вийти з ладу цікавими способами, коли VARмістить спеціальні символи.

awkРобоча indexфункція повинна вміти робити трюк. Але все це здається занадто важким для такої легкої перевірки.


[[робить regexp, так що ти починаєшwith [[$ PWD = ~ ^ \ / home \ /]]
tekpapaul

0

Якщо знайдена шукана частина шляху, я "порожню" змінну:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.