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


25

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

Respostas:


26

Se você deseja testar com segurança se um diretório é um subdiretório de outro, precisará de mais do que apenas uma verificação de prefixo de sequência. A resposta de Gilles descreve em detalhes como fazer esse teste corretamente.

Mas se você deseja uma verificação simples do prefixo de sequência (talvez você já tenha normalizado seus caminhos?), Esta é uma boa:

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

Se $PWDcomeçar com "/ home /", ele será retirado do lado esquerdo, o que significa que não corresponderá ao lado direito, então "! =" Retornará verdadeiro.


11
+1 perfeito, e para um caso mais geral: [ "${PWD##$VAR}" != "$PWD" ]e se essa fosse uma pergunta [code-golf] ( stackoverflow.com/questions/tagged/code-golf)), você teria me vencido em dois caracteres ;-) Também parece mais legível ...
Tobias Kienzler 26/01

FWIW, isso também pode ser útil:${PWD/#$HOME/\~}
user1338062

Tudo bem, mas que tal PWD = "/ home /../ etc /" #
Alexis Peters #

11
@ AlexisPeters: Você está certo: eu estava focando na parte "prefixo de string" da pergunta e editei para deixar isso mais claro. Gilles cobriu bem a maneira correta de verificar subdiretórios.
Jander

11
Use "${PWD%%/subdir*}"para detectar se o usuário está atualmente em subdirou em um subdiretório de subdir, pois %% captura do final da sequência em vez do início. Isso deve ser útil para qualquer pessoa à procura de mais informações sobre a substituição de parâmetros: tldp.org/LDP/abs/html/parameter-substitution.html
George Pantazes

33

Para testar se uma string é um prefixo de outra, em qualquer shell no 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 caseconstruções, diferente dos nomes dos arquivos, *corresponde a qualquer caractere, incluindo um /ou uma inicial ..

Nos shells que implementam a [[ … ]]sintaxe (ou seja, bash, ksh e zsh), ele pode ser usado para combinar uma string com um padrão. (Observe que o [comando só pode testar cadeias de caracteres para igualdade.)

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

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

Se /homefor 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ê possui o NetBSD, OpenBSD ou GNU (ou seja, Linux) readlink, pode usar readlink -fpara remover links simbólicos de um caminho.

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

Caso contrário, você pode usar pwdpara mostrar o diretório atual. Mas você deve tomar cuidado para não usar um shell interno se o seu shell rastrear cdcomandos e manter o nome que você usou para acessar o diretório em vez de sua localização "real".

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

+1 Obrigado por esta resposta exaustiva. Eu não considero links e peculiaridades do sistema de arquivos quando perguntando isso, mas é definitivamente bom saber
Tobias KIENZLER

8

Versão bruta:

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

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

editar (obrigado @ Michael) pela generalização para comparar com $VARum pode usar

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

4
${#var}é o comprimento de $var, para que você possa generalizá-lo como[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek

@ Michael Mrozek ♦: Obrigado, funciona perfeito :)
Tobias KIENZLER

2

Eu não entendo 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 ...


Isso só funcionaria se eu soubesse a profundidade, caso contrário, acabarei com /. Ok, eu poderia verificar recursivamente, mas não há algo mais fácil?
Tobias Kienzler

11
@tob Se eu soubesse programação shell ;-)
tshepang

1

Usando awk:

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'

+1 para trabalhar, mas um pouco mais lento do que um teste de festa nativa
Tobias KIENZLER

0

Hum, é uma pena que [não tenha uma opção de testar a STRING1 starts with STRING2condição.

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

awkA indexfunção de deve poder executar o truque. Mas tudo isso parece pesado demais para uma coisa tão fácil de testar.


[[regexp para que você comece com [[$ PWD = ~ ^ \ / home \ /]]
teknopaul 2/15/15

0

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

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.