A condizione che tu abbia i permessi di esecuzione sulla directory corrente - o sulla directory da cui hai eseguito lo script della shell - se vuoi un percorso assoluto in una directory tutto ciò di cui hai bisogno è cd
.
Passaggio 10 delle cd
specifiche
Se l' -P
opzione è attiva, la $PWD
variabile di ambiente deve essere impostata sulla stringa che verrebbe prodotta da pwd -P
. Se l'autorizzazione non è sufficiente sulla nuova directory, o su qualsiasi genitore di quella directory, per determinare la directory di lavoro corrente, il valore della $PWD
variabile di ambiente non è specificato.
E via pwd -P
Il percorso scritto nello standard output non deve contenere alcun componente che faccia riferimento a file di tipo link simbolico. Se esistono più percorsi che l' pwd
utilità potrebbe scrivere sullo standard output, uno che inizia con un carattere singolo / barra e uno o più che iniziano con due caratteri / barra, allora deve scrivere il percorso che inizia con un carattere singolo / barra. Il nome del percorso non deve contenere caratteri non necessari / barra dopo il primo o due caratteri / barra.
È perché cd -P
deve impostare la directory di lavoro corrente su ciò che pwd -P
dovrebbe altrimenti stampare e che cd -
deve stampare $OLDPWD
quanto segue:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
PRODUZIONE
/home/mikeserv/test/ln
aspettalo...
cd -P . ; cd . ; cd -
PRODUZIONE
/home/mikeserv/test/dir
E quando stampo con cd -
sto stampando $OLDPWD
. cd
imposta $PWD
non appena cd -P .
$PWD
ora sono un percorso assoluto per /
- quindi non ho bisogno di altre variabili. E in realtà, devo neppure bisogno della finale .
ma c'è un comportamento specificata di reset $PWD
a $HOME
in una shell interattiva quando cd
è disadorna. Quindi è solo una buona abitudine da sviluppare.
Quindi semplicemente fare quanto sopra sul percorso in ${0%/*}
dovrebbe essere più che sufficiente per verificare $0
il percorso, ma nel caso che $0
sia esso stesso un soft-link, probabilmente non è possibile cambiare directory in esso, sfortunatamente.
Ecco una funzione che gestirà ciò:
zpath() { cd -P . || return
_out() { printf "%s$_zdlm\n" "$PWD/${1##*/}"; }
_cd() { cd -P "$1" ; } >/dev/null 2>&1
while [ $# -gt 0 ] && _cd .
do if _cd "$1"
then _out
elif ! [ -L "$1" ] && [ -e "$1" ]
then _cd "${1%/*}"; _out "$1"
elif [ -L "$1" ]
then ( while set -- "${1%?/}"; _cd "${1%/*}"; [ -L "${1##*/}" ]
do set " $1" "$(_cd -; ls -nd -- "$1"; echo /)"
set -- "${2#*"$1" -> }"
done; _out "$1"
); else ( PS4=ERR:\ NO_SUCH_PATH; set -x; : "$1" )
fi; _cd -; shift; done
unset -f _out _cd; unset -v _zdlm
}
Si sforza di fare tutto ciò che potrebbe nella shell corrente - senza invocare una subshell - anche se ci sono subshells invocate per errori e collegamenti software che non puntano alle directory. Dipende da una shell compatibile con POSIX e compatibile ls
con POSIX e da uno _function()
spazio dei nomi pulito . Funzionerà ancora bene senza quest'ultimo, anche se potrebbe sovrascrivere quindi unset
alcune funzioni shell correnti in quel caso. In generale, tutte queste dipendenze dovrebbero essere disponibili in modo abbastanza affidabile su una macchina Unix.
Chiamata con o senza argomenti, la prima cosa che fa è reimpostare il $PWD
suo valore canonico - risolve tutti i collegamenti in essa contenuti ai loro obiettivi, se necessario. Chiamato senza argomenti e questo è tutto; ma chiamato con loro e risolverà e canonicalizzerà il percorso per ognuno oppure stampa un messaggio sul stderr
perché no.
Poiché funziona principalmente nella shell corrente, dovrebbe essere in grado di gestire un elenco di argomenti di qualsiasi lunghezza. Cerca anche la $_zdlm
variabile (che è anche unset
quando è passata) e stampa il suo valore con escape in C immediatamente a destra di ciascuno dei suoi argomenti, ognuno dei quali è sempre seguito anche da un singolo \n
carattere di ewline.
Fa molte modifiche alla directory, ma, oltre a impostarlo sul suo valore canonico, non influisce $PWD
, sebbene $OLDPWD
non possa in alcun modo essere contato quando è passato.
Tenta di abbandonare ciascuno dei suoi argomenti il prima possibile. Per prima cosa cerca di cd
entrare $1
. Se ci riesce, stampa il percorso canonico dell'argomento stdout
. In caso contrario, verifica che $1
esista e non sia un collegamento software. Se vero, stampa.
In questo modo gestisce qualsiasi argomento relativo al tipo di file che la shell ha i permessi da affrontare a meno che non $1
sia un collegamento simbolico che non punta a una directory. In tal caso, chiama while
loop in una subshell.
Chiama ls
per leggere il link. La directory corrente deve essere cambiata prima al suo valore iniziale per gestire in modo affidabile qualsiasi percorso di riferimento e quindi, nella sottostruttura di sostituzione comandi la funzione fa:
cd -...ls...echo /
Elimina dalla sinistra ls
dell'output il minimo necessario per contenere completamente il nome e la stringa del collegamento ->
. Mentre all'inizio ho cercato di evitare di farlo shift
e $IFS
risulta che questo è il metodo più affidabile il più vicino possibile. Questa è la stessa cosa che fa il povero_mans_readlink di Gilles - ed è ben fatto.
Ripeterà questo processo in un ciclo fino a quando il nome file restituito ls
non è sicuramente un collegamento software. A quel punto canonicalizza quel percorso come prima con cd
poi le stampe.
Esempio di utilizzo:
zpath \
/tmp/script \ #symlink to $HOME/test/dir/script.sh
ln \ #symlink to ./dir/
ln/nl \ #symlink to ../..
/dev/fd/0 \ #currently a here-document like : dash <<\HD
/dev/fd/1 \ #(zlink) | dash
file \ #regular file
doesntexist \ #doesnt exist
/dev/disk/by-path/pci-0000:00:16.2-usb-0:3:1.0-scsi-0:0:0:0 \
/dev/./././././././null \
. ..
PRODUZIONE
/home/mikeserv/test/dir/script.sh
/home/mikeserv/test/dir/
/home/mikeserv/test/
/tmp/zshtpKRVx (deleted)
/proc/17420/fd/pipe:[1782312]
/home/mikeserv/test/file
ERR: NO_SUCH_PATH: doesntexist
/dev/sdd
/dev/null
/home/mikeserv/test/
/home/mikeserv/
O forse ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
PRODUZIONE
/home/mikeserv/test/dir/^@$
/home/mikeserv/test/file^@$
/home/mikeserv/test/file$
^@$
/home/mikeserv/test/folder/^@$
/home/mikeserv/test/file$ #'link' -> 'file\n'
^@$
/home/mikeserv/test/dir/^@$ #'ln' -> './dir'
/home/mikeserv/test/script^@$
/home/mikeserv/test/dir/script.sh^@$ #'script3' -> './dir/script.sh'
/home/mikeserv/test/dir/script.sh^@$ #'script4' -> '/tmp/script' -> ...