Как проверить, является ли $ PWD подкаталогом данного пути

25

Например, проверьте, $PWDявляется ли подкаталог / home. Другими словами, я ищу операцию строки bash, чтобы проверить, начинается ли одна строка с другой.

Тобиас Кинцлер
источник

Ответы:

26

Если вы хотите надежно проверить, является ли каталог подкаталогом другого, вам потребуется нечто большее, чем просто проверка префикса строки. Ответ Жиля подробно описывает, как правильно выполнить этот тест.

Но если вам нужна простая проверка префикса строки (может быть, вы уже нормализовали свои пути?), Это хорошо:

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

Если $PWDначинается с "/ home /", он удаляется с левой стороны, что означает, что он не будет совпадать с правой стороной, поэтому "! =" Возвращает true.

Jander
источник
1
+1 идеально, и для более общего случая: [ "${PWD##$VAR}" != "$PWD" ]И если бы это был [code-golf] ( stackoverflow.com/questions/tagged/code-golf)question, вы бы меня избили двумя символами ;-) Также это выглядит более читабельно ...
Тобиас Кинцлер
FWIW, это также может быть полезно:${PWD/#$HOME/\~}
user1338062
Хорошо, но как насчет PWD = "/ home /../ и т.д. /"
Алексис Питерс
1
@AlexisPeters: Вы правы: я сосредоточился на части вопроса «префикс строки», и я отредактировал, чтобы сделать это более ясным. Жиль хорошо описал правильный способ проверки подкаталогов.
Jander
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конструкциях, в отличие от имен файлов, *совпадает любой символ, включая /или начальный ..

В оболочках, которые реализуют [[ … ]]синтаксис (т. Е. 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 Спасибо за этот исчерпывающий ответ. Я не
учел
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)и так далее ...

tshepang
источник
Это сработало бы, только если бы я знал глубину, иначе я бы в итоге /. Хорошо, я могу проверить рекурсивно, но разве нет ничего проще?
Тобиас Кинцлер
1
@tob Если бы я только знал программирование оболочки ;-)
tshepang
1

Использование awk:

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'
кендырь
источник
+1 за работу, но немного медленнее, чем собственный тест на bash
Тобиас Кинцлер
0

Хм, жаль, что [нет возможности проверить STRING1 starts with STRING2условие.

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

awk«S indexфункция должна быть в состоянии сделать трюк. Но все это кажется слишком тяжелым для такой легкой вещи, чтобы проверить.

Алекс
источник
[[делает регулярное выражение, чтобы вы начали с [[$ PWD = ~ ^ \ / home \ /]]
teknopaul
0

Если найденная часть пути найдена, я «очищаю» переменную:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"

источник