За умови, що у вас є дозволи на виконання поточного каталогу - або в каталозі, з якого ви виконали сценарій оболонки - якщо ви хочете абсолютний шлях до каталогу, все, що вам потрібно cd
.
Крок 10 cd
специфікації
Якщо -P
опція діє, $PWD
змінна середовища повинна бути встановлена на рядок, з якого виводиться pwd -P
. Якщо в новому каталозі або в будь-якому з батьків цього каталогу недостатньо дозволу, щоб визначити поточну робочу директорію, значення$PWD
змінної середовища не визначено.
І далі pwd -P
Ім'я шляху, записане на стандартний вихід, не повинно містити компонентів, що посилаються на файли символьного посилання типу. Якщо є кілька імен,pwd
утиліта могла записати на стандартний вихід, один, що починається з одного символу / косою рисою, і один або більше початку з двома символами / косою рисою, то він повинен записувати ім'я шляху, що починається з символу одиночної / косою / косою. Ім'я контуру не повинно містити зайвих символів / косою рискою після провідних одного або двох символів / косою рисою.
Це тому , що cd -P
має встановити поточну робочу директорію на те , що в pwd -P
іншому випадку слід роздрукувати і що cd -
має надрукувати , $OLDPWD
що такі роботи:
mkdir ./dir
ln -s ./dir ./ln
cd ./ln ; cd . ; cd -
ВИХІД
/home/mikeserv/test/ln
зачекайте ...
cd -P . ; cd . ; cd -
ВИХІД
/home/mikeserv/test/dir
І коли я друкую, cd -
я друкую $OLDPWD
. cd
встановлюється, $PWD
як тільки я cd -P .
$PWD
зараз став абсолютним шляхом /
- тому мені не потрібні інші змінні. І на насправді, я навіть не потрібна буксирування , .
але є заданий поведінка скидання $PWD
в$HOME
в інтерактивній оболонці , коли cd
це оздоби. Так що це лише гарна звичка розвиватися.
Тому просто робити вищезазначене на шляху в ${0%/*}
має бути більш ніж достатньо для перевірки $0
шляху, але у випадку цього$0
вона сама є софт-посиланням, ви, мабуть, не можете змінити каталог у неї, на жаль.
Ось функція, яка впорається з цим:
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
}
Він прагне зробити стільки, наскільки це можливо в поточній оболонці - без виклику підкашлю - хоча є підрозділи, на які посилаються помилки та м'які посилання, які не вказують на каталоги. Це залежить від POSIX-сумісної оболонки та POSIX-сумісної ls
, а також чистої_function()
простору імен. Він все одно буде функціонувати просто без останнього, хоча unset
в цьому випадку він може перезаписати деякі поточні функції оболонки. Взагалі всі ці залежності повинні бути досить надійно доступними на машині Unix.
Викликаний з аргументами або без них, перше, що він робить, - це скинути $PWD
його канонічне значення - він вирішує будь-які посилання в ньому на цілі, якщо це необхідно. Викликається без аргументів, і це про це; але зателефонуйте з ними, і це дозволить вирішити і канонізувати шлях для кожного або іншого друку повідомленняstderr
чому б ні.
Оскільки він здебільшого працює в поточній оболонці, він повинен мати можливість обробляти список аргументів будь-якої довжини. Він також шукає $_zdlm
змінну (яку вона також unset
проходить, коли вона проходить) і надрукує її значення, що уникнуло С, відразу ж праворуч від кожного з його аргументів, за кожним з яких завжди також йде один \n
символ ewline.
Це робить багато змін каталогів, але, крім встановлення його канонічного значення, це не впливає $PWD
, хоча $OLDPWD
жодним чином не може розраховуватись, коли він проходить.
Він намагається залишити кожен із своїх аргументів якнайшвидше. Вона спочатку намагається cd
в $1
. Якщо він може, він надрукує канонічний шлях аргументу до stdout
. Якщо він не може, він перевіряє, що $1
існує, і це не м'яке посилання. Якщо це правда, він друкує.
Таким чином, він обробляє будь-який аргумент типу файлу, на який оболонка має дозволи на адресу, якщо тільки $1
це символічне посилання, яке не вказує на каталог. У такому випадку він викликає while
цикл у підзарядці.
Він закликає ls
прочитати посилання. Поточний каталог спочатку потрібно змінити на його початкове значення, щоб надійно обробити будь-які референтні шляхи, і таким чином, в підзакритті підстановки команд функція виконує:
cd -...ls...echo /
Він видаляється зліва від ls
вихідного сигналу настільки ж мало, наскільки він повинен повністю містити ім'я посилання та рядок ->
. Хоча я спершу намагався уникати цього, shift
і $IFS
виявляється, це найнадійніший метод, наскільки я можу зрозуміти. Це те саме, що робить поганий_літовий посилання Гілла - і це добре зроблено.
Він буде повторювати цей процес у циклі, поки ім'я файлу, повернене з ls
нього, точно не є м'яким посиланням. У цей момент вона канонізує цей шлях, як і раніше, після cd
цього друкує.
Приклад використання:
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 \
. ..
ВИХІД
/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/
Або можливо ...
ls
dir/ file file? folder/ link@ ln@ script* script3@ script4@
zdlm=\\0 zpath * | cat -A
ВИХІД
/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' -> ...