Como verificar se $ PWD é um subdiretório de um determinado caminho

23

Por exemplo verifique se $PWD é um subdiretório de / home. Em outras palavras, estou procurando uma operação de string bash para verificar se uma string começa com outra.

    
por Tobias Kienzler 25.01.2011 / 16:18

7 respostas

24

Se você quiser testar com confiabilidade se um diretório é um subdiretório de outro, precisará de mais do que apenas uma verificação de prefixo de cadeia. A resposta de Gilles descreve em detalhes como fazer esse teste adequadamente.

Mas se você quiser uma verificação de prefixo de cadeia simples (talvez você já tenha normalizado seus caminhos?), esta é uma boa:

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

Se $PWD começar com "/ home /", ele será removido no lado esquerdo, o que significa que ele não corresponderá ao lado direito, então "!=" retorna verdadeiro.

    
por 25.01.2011 / 16:59
29

Para testar se uma string é um prefixo de outra, em qualquer shell do estilo Bourne:

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

O mesmo princípio funciona para um teste de sufixo ou substring. Observe que, nas construções case , diferentemente dos nomes de arquivos, * corresponde a qualquer caractere, incluindo / ou inicial . .

Em shells que implementam a sintaxe [[ … ]] (ou seja, bash, ksh e zsh), ela pode ser usada para corresponder uma string a um padrão. (Observe que o comando [ só pode testar strings para igualdade.)

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

Se você estiver testando especificamente se o diretório atual está abaixo de /home , um teste simples de substring não é suficiente, devido a links simbólicos.

Se /home for um sistema de arquivos próprio, teste se o diretório atual ( . ) está nesse sistema de arquivos.

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

Se você tem o NetBSD, OpenBSD ou GNU (ou seja, Linux) readlink , você pode usar readlink -f para remover links simbólicos de um caminho.

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

Caso contrário, você pode usar pwd para mostrar o diretório atual. Mas você deve tomar cuidado para não usar um shell embutido se o seu shell rastreia os comandos cd e mantém o nome que você usou para alcançar o diretório ao invés de seu local "real".

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) …
    
por 25.01.2011 / 21:38
7

Versão bruta:

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

Tem a desvantagem de primeiro contar os caracteres e um não pode substituir /home/ por algo geral como $1 .

edit (obrigado @Michael) pela generalização para comparar com $VAR que se pode usar

[ "${PWD:0:${#VAR}}" = $VAR ]
    
por 25.01.2011 / 16:48
1

Usando awk :

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'
    
por 25.01.2011 / 17:25
0

Eu não entendi a pergunta muito bem, mas para encontrar o pai de $ PWD , faça dirname $PWD . Para encontrar o pai do pai, execute dirname $(dirname $PWD) e assim por diante ...

    
por 25.01.2011 / 16:31
0

Hm, é pena que [ não tenha uma opção de testar a condição STRING1 starts with STRING2 .

Você pode tentar echo $PWD | grep '^$VAR' , mas pode falhar de formas interessantes quando VAR contém símbolos especiais.

A função awk do index deve ser capaz de fazer o truque. Mas tudo isso parece pesado demais para uma coisa tão fácil de testar.

    
por 25.01.2011 / 17:09
0

Se a parte pesquisada do caminho for encontrada, eu "esvazio" a variável:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
    
por 25.01.2011 / 17:49