Controlla se due percorsi sono uguali, anche se le loro stringhe non corrispondono esattamente


0

Ho uno script che dipende da alcune variabili d'ambiente, alcune delle quali sono percorsi

Lo script controlla se viene eseguito nella directory corretta controllando $(pwd)/expected-subdircontro$VARIABLE_PATH/expected_subdir

Ovviamente se $VARIABLE_PATH == $(pwd)/(naturalmente ho aggiunto una barra alla fine della variabile durante la digitazione), la corrispondenza della stringa fallisce anche se le directory sono tecnicamente sane.

C'è un modo per identificare in modo univoco una directory, dare un percorso ad essa e vedere se un altro percorso ti indirizzerà allo stesso punto? È possibile che il percorso indicato non sia sano, quindi questo controllo dovrebbe ancora essere fatto, ma sembra inutile forzare la corrispondenza esatta del percorso, quando una barra vagante o anche una relativa directory (so che a volte possono essere cattivi) ti indirizzerebbe nello stesso punto.

Risposte:


1

Quest'altra risposta menziona stat. Miglioriamo l'approccio:

a="$(stat --format=%d:%i -- "$(pwd)/expected-subdir/")"         || printf "Error A\n" >&2
b="$(stat --format=%d:%i -- "$VARIABLE_PATH/expected-subdir/")" || printf "Error B\n" >&2
[ "$a" = "$b" ] || printf "Not the same path.\n" >&2

Gli appunti:

  • Stiamo utilizzando stat --format=, quindi non sono necessari ulteriori analisi.
  • %dè il numero del dispositivo, %iè il numero dell'inode. Quest'ultimo da solo non è sufficiente perché due oggetti su dispositivi diversi (filesystem) possono avere lo stesso numero di inode.
  • La shell è abbastanza intelligente da gestire separatamente le virgolette dentro e fuori $( ).
  • printf-s sono solo matrici per la gestione degli errori. Nella vera sceneggiatura probabilmente vorresti qualcosa del genere

    [ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }
  • Il percorso inesistente causerà statun errore.

  • Le barre finali sono importanti. Se fooè un collegamento simbolico a una directory, stat fooesaminerà il collegamento simbolico mentre stat foo/esaminerà la directory. In alternativa, cerca stat -Le usalo forse.
  • --è nel caso $(pwd)o $VARIABLE_PATHinizia con -(vedere la linea guida 10 qui ).

Ci sono readlink -f(anche menzionati nell'altra risposta) e realpathutilità. Uno di questi potrebbe essere un approccio migliore di stat. Dipende da quali aspetti dei percorsi sono importanti per te. Differenze principali:

  1. Se /foo/bar/è un attacco bind, /moo/baz/allora stat --format=%d:%iti dirà che sono uguali, ma readlinko realpathli considererà diversi.
  2. La situazione si complica con i collegamenti simbolici e ... Vedi man 1 realpath, in particolare -Le le -Popzioni.

Con i link simbolici coinvolti, se il tuo script modifica la directory verso l'alto (verso /, ad esempio cd ..), potresti ottenere risultati diversi a seconda di dove inizi, anche se stato readlink -fdice che i due punti di partenza sono gli stessi (confronta Perché ls ..mostra il vero contenuto genitore quando io ' m all'interno di una directory di link simbolici? ). Considera questo approccio:

# early in the script
set -P
cd .   # seems like no-op but updates the PWD variable to physical path

Con i montaggi di bind coinvolti, se lo script modifica la directory, potresti ottenere risultati diversi a seconda di dove inizi, anche se statdice che i due punti di partenza sono gli stessi. Considera l'esempio con /foo/bar/e /moo/baz/(già introdotto sopra). È ovvio che /foo/potrebbe essere completamente diverso da /moo/. Ma /foo/bar/abcpuò anche essere diverso dal /moo/baz/abcfatto che qualsiasi abcpotrebbe essere un attacco indipendente a qualcos'altro. Quindi non solo cd ..potresti metterti in un posto diverso, ma anche cd abc.

Bene, abcpotrebbe essere un file. Cosa succede se si associa un altro file a /moo/baz/abcma non a /foo/bar/abc? I file percepiti saranno diversi anche se statdice che sei nello stesso posto!

A causa di questi problemi potresti davvero preferire readlinko realpathesagerare stat.


stat, readlinkE realpathnon sono richieste, POSIX. Nel tuo caso una soluzione portatile può apparire così:

a="$(cd -P -- "expected-subdir" && pwd -P)"                || exit 1
b="$(cd -P -- "$VARIABLE_PATH/expected-subdir" && pwd -P)" || exit 1
[ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }

Funziona andando cdsu entrambi i percorsi e recuperandolo pwd. Queste operazioni sono esplicitamente costrette ad agire "fisicamente" ( -P).

set -Pnon è neanche POSIX. Se si desidera "emulare" la shell POSIX set -P, sostituire cde pwd:

cd()  { command cd  -P "$@"; }
pwd() { command pwd -P "$@"; }

POSIX richiede che l'ultimo -Po l' -Lopzione abbia effetto, quindi pwd -Lrecupera comunque il percorso logico anche se la funzione "inietta" -P; lo stesso per cd -L.


1

È possibile confrontare i loro numeri di inode, che possono essere ottenuti da ls -i

ls -di path/to/dir

( -dimpedisce lsdi mostrare gli ID inode per il contenuto della directory);

o da stat

stat path/to/dir | grep -o 'Inode:\ [0-9]*' | cut -d' ' -f2

È inoltre possibile utilizzare readlink -fper ottenere il percorso completo della directory.


Per gli script, potrebbe essere più facile da usare in find path/to/dir/ -maxdepth 0 -printf %i\\nquanto stampa solo l'inode e non il nome. Il maxdepth 0impedisce una profonda ricerca. Per maggiore sicurezza, aggiungi %Dpoiché gli inode sono unici per disco, non a livello di sistema.
MSalter
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.