So prüfen Sie, ob $ PWD ein Unterverzeichnis eines bestimmten Pfades ist

25

Überprüfen Sie beispielsweise, ob $PWDes sich um ein Unterverzeichnis von / home handelt. Mit anderen Worten, ich suche nach einer Bash-String-Operation, um zu überprüfen, ob ein String mit einem anderen beginnt.

Tobias Kienzler
quelle

Antworten:

26

Wenn Sie zuverlässig testen möchten, ob ein Verzeichnis ein Unterverzeichnis eines anderen ist, benötigen Sie mehr als nur eine Zeichenfolgepräfixprüfung. In der Antwort von Gilles wird ausführlich beschrieben, wie dieser Test ordnungsgemäß durchgeführt wird.

Wenn Sie jedoch eine einfache Überprüfung des Zeichenfolgepräfixes wünschen (haben Sie Ihre Pfade möglicherweise bereits normalisiert?), Ist dies eine gute Option:

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

Wenn $PWDmit "/ home /" begonnen wird, wird es auf der linken Seite entfernt, was bedeutet, dass es nicht mit der rechten Seite übereinstimmt. "! =" Gibt also true zurück.

Jander
quelle
1
+1 perfekt, und für einen allgemeineren Fall: [ "${PWD##$VAR}" != "$PWD" ]Und wenn dies eine [Code-Golf] ( stackoverflow.com/questions/tagged/code-golf ) -Frage wäre, hättest du mich um zwei Zeichen geschlagen ;-) Sieht auch so aus lesbarer ...
Tobias Kienzler
FWIW, dies kann auch nützlich sein:${PWD/#$HOME/\~}
user1338062
Okay, aber wie wäre es mit PWD = "/ home /../ etc /"
Alexis Peters
1
@AlexisPeters: Sie haben Recht: Ich habe mich auf den Teil "Zeichenfolgepräfix" der Frage konzentriert und ihn bearbeitet, um dies deutlicher zu machen. Gilles hat den richtigen Weg zur Suche nach Unterverzeichnissen beschrieben.
Jander
1
Wird verwendet "${PWD%%/subdir*}", um zu ermitteln, ob sich der Benutzer derzeit in subdiroder in einem Unterverzeichnis von befindet subdir, da %% vom Ende der Zeichenfolge statt vom Anfang erfasst wird. Dies sollte für alle nützlich sein, die weitere Informationen zur Parametersubstitution benötigen
George Pantazes
33

So testen Sie in einer beliebigen Bourne-Shell, ob eine Zeichenfolge ein Präfix einer anderen ist:

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

Das gleiche Prinzip gilt für einen Suffix- oder Teilzeichenfolgetest. Beachten Sie, dass in caseKonstrukten im Gegensatz zu Dateinamen *jedes Zeichen, einschließlich eines /oder einer Initiale , übereinstimmt ..

In Shells, die die [[ … ]]Syntax implementieren (z. B. bash, ksh und zsh), kann eine Zeichenfolge mit einem Muster verglichen werden. (Beachten Sie, dass der [Befehl nur Zeichenfolgen auf Gleichheit testen kann.)

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

Wenn Sie speziell testen, ob sich das aktuelle Verzeichnis darunter befindet /home, reicht ein einfacher Teilzeichenfolgetest aufgrund symbolischer Verknüpfungen nicht aus.

Wenn /homees sich um ein eigenes Dateisystem handelt, prüfen Sie, ob sich das aktuelle Verzeichnis ( .) auf diesem Dateisystem befindet.

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

Wenn Sie NetBSD, OpenBSD oder GNU (dh Linux) haben readlink, können Sie readlink -fsymbolische Links von einem Pfad entfernen.

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

Andernfalls können Sie pwddas aktuelle Verzeichnis anzeigen. Sie müssen jedoch darauf achten, keine eingebaute Shell zu verwenden, wenn Ihre Shell cdBefehle verfolgt und den Namen beibehält, den Sie zum Erreichen des Verzeichnisses verwendet haben, anstatt den „tatsächlichen“ Speicherort.

case $(pwd -P 2>/dev/null || env PWD= pwd)/ in
  "$(cd /home && { pwd -P 2>/dev/null || env PWD= pwd; })"/*) 
Gilles 'SO - hör auf böse zu sein'
quelle
+1 Danke für diese ausführliche Antwort. Ich habe Links und Dateisystem-Besonderheiten nicht berücksichtigt, aber es ist auf jeden Fall gut zu wissen
Tobias Kienzler
8

Rohversion:

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

Hat den Nachteil, dass man zuerst die Zeichen zählen muss und nicht /home/durch etwas allgemeines wie ersetzen kann $1.

edit (danke @Michael) für die verallgemeinerung die man zum vergleichen $VARbenutzen kann

[ "${PWD:0:${#VAR}}" = $VAR ]
Tobias Kienzler
quelle
4
${#var}ist die Länge von $var, also können Sie es verallgemeinern als[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek
@Michael Mrozek ♦: Danke, funktioniert perfekt :)
Tobias Kienzler
2

Ich verstehe die Frage nicht so gut, aber um die Eltern von $ PWD zu finden , tun Sie es dirname $PWD. Führen Sie dirname $(dirname $PWD)usw. aus, um das übergeordnete Element des übergeordneten Elements zu finden.

Tshepang
quelle
Das würde nur klappen, wenn ich die Tiefe wüsste, sonst lande ich bei /. Ok, ich könnte rekursiv prüfen, aber gibt es nicht etwas einfacheres?
Tobias Kienzler
1
@tob Wenn ich nur Shell-Programmierung wüsste
;-)
1

Verwenden von awk:

echo $PWD | awk -v h="/home" '$0 ~ h {print "MATCH"}'
Dogbane
quelle
+1 für die Arbeit, aber ein bisschen langsamer als ein nativer Bash-Test
Tobias Kienzler
0

Hm, es ist schade, dass [es keine Möglichkeit gibt, STRING1 starts with STRING2Bedingungen zu testen .

Sie können es versuchen echo $PWD | grep '^$VAR', aber es kann auf interessante Weise scheitern, wenn es VARspezielle Symbole enthält.

awkDie indexFunktion von sollte in der Lage sein, den Trick auszuführen. Aber das alles scheint einfach zu schwer, als dass es so einfach zu testen wäre.

Alex
quelle
[[regexp, damit du mit [[$ PWD = ~ ^ \ / home \ /]]
startest
0

Wenn der gesuchte Teil des Pfades gefunden wird, "entleere" ich die Variable:

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

quelle