За умови, що у вас є дозволи на виконання поточного каталогу - або в каталозі, з якого ви виконали сценарій оболонки - якщо ви хочете абсолютний шлях до каталогу, все, що вам потрібно 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' -> ...