Come verificare se $ PWD è una sottodirectory di un determinato percorso


25

Ad esempio, controlla se $PWDè una sottodirectory di / home. In altre parole, sto cercando un'operazione di stringa bash per verificare se una stringa inizia con un'altra.

Risposte:


26

Se si desidera verificare in modo affidabile se una directory è una sottodirectory di un'altra, è necessario più di un semplice controllo prefisso stringa. La risposta di Gilles descrive in dettaglio come eseguire correttamente questo test.

Ma se vuoi un semplice controllo prefisso stringa (forse hai già normalizzato i tuoi percorsi?), Questo è buono:

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

Se $PWDinizia con "/ home /", viene rimosso nella parte sinistra, il che significa che non corrisponderà alla parte destra, quindi "! =" Restituisce true.


1
+1 perfetto, e per un caso più generale: [ "${PWD##$VAR}" != "$PWD" ]E se questo fosse un [code-golf] ( stackoverflow.com/questions/tagged/code-golf)question mi avresti battuto di due caratteri ;-) Inoltre sembra più leggibile ...
Tobias Kienzler,

FWIW, questo può anche essere utile:${PWD/#$HOME/\~}
user1338062

Va bene, ma che ne dici di PWD = "/ home /../ etc /"
Alexis Peters

1
@AlexisPeters: Hai ragione: mi sono concentrato sulla parte "prefisso stringa" della domanda, e ho modificato per renderlo più chiaro. Gilles ha ben coperto il modo corretto di verificare le sottodirectory.
Jander

1
Utilizzare "${PWD%%/subdir*}"per rilevare se l'utente è attualmente in subdiro in una sottodirectory di subdir, poiché %% acquisisce dalla fine della stringa anziché dall'inizio. Questo dovrebbe essere utile a chiunque cerchi maggiori informazioni sulla sostituzione dei parametri: tldp.org/LDP/abs/html/parameter-substitution.html
George Pantazes,

33

Per verificare se una stringa è un prefisso di un'altra, in qualsiasi shell in stile Bourne:

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

Lo stesso principio funziona per un suffisso o un test di sottostringa. Si noti che nei casecostrutti, diversamente dai nomi dei file, *corrisponde a qualsiasi carattere, incluso un /o un iniziale ..

Nelle shell che implementano la [[ … ]]sintassi (cioè bash, ksh e zsh), può essere usato per abbinare una stringa a uno schema. (Notare che il [comando può solo testare le stringhe per l'uguaglianza.)

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

Se stai verificando specificamente se la directory corrente è sotto /home, un semplice test di sottostringa non è sufficiente, a causa di collegamenti simbolici.

Se /homeè un file system a sé stante, verifica se la directory corrente ( .) si trova su quel file system.

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

Se si dispone di NetBSD, OpenBSD o GNU (ad esempio Linux) readlink, è possibile utilizzare readlink -fper rimuovere i collegamenti simbolici da un percorso.

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

Altrimenti, è possibile utilizzare pwdper mostrare la directory corrente. Ma devi fare attenzione a non usare una shell incorporata se la shell tiene traccia dei cdcomandi e mantiene il nome che hai usato per raggiungere la directory piuttosto che la sua posizione “effettiva”.

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

+1 Grazie per questa risposta esaustiva. Non ho preso in considerazione i collegamenti e le peculiarità del filesystem quando lo ho chiesto, ma è sicuramente buono a sapersi
Tobias Kienzler,

8

Versione grezza:

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

Ha lo svantaggio di dover prima contare i personaggi e non si può sostituire /home/con qualcosa di simile $1.

modifica (grazie @Michael) per la generalizzazione da confrontare con $VARuno che puoi usare

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

4
${#var}è la lunghezza di $var, quindi puoi generalizzarlo come[ "${PWD:0:${#1}}" = "$1" ]
Michael Mrozek

@Michael Mrozek ♦: Grazie, funziona perfettamente :)
Tobias Kienzler,

2

Non capisco bene la domanda, ma per trovare il genitore di $ PWD , fallo dirname $PWD. Per trovare il genitore del genitore, esegui dirname $(dirname $PWD)e così via ...


Funzionerebbe solo se conoscessi la profondità, altrimenti finirò con /. Ok, potrei controllare ricorsivamente, ma non c'è qualcosa di più facile?
Tobias Kienzler,

1
@tob Se solo conoscessi la programmazione della shell ;-)
tshepang

1

Utilizzando awk:

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

+1 per lavoro, ma un po 'più lento di un test bash nativo
Tobias Kienzler,

0

E 'un peccato che [non abbia un'opzione per testare le STRING1 starts with STRING2condizioni.

Puoi provare echo $PWD | grep '^$VAR', ma può fallire in modi interessanti quando VARcontiene simboli speciali.

awkLa indexfunzione dovrebbe essere in grado di fare il trucco. Ma tutto ciò sembra troppo pesante per una cosa così facile da testare.


[[regexp in modo da iniziare con [[$ PWD = ~ ^ \ / home \ /]]
teknopaul

0

Se viene trovata la parte cercata del percorso, "svuoto" la variabile:

[[ -z "${PWD//*\/home\/*/}" ]] && echo "toto"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.