Отримати шлях поточного сценарію при виконанні через симпосилання


58

У мене є утиліта, що складається з декількох каталогів з деякими скриптами bash та допоміжними файлами, які будуть розгорнуті на декількох машинах, можливо, в іншому каталозі на кожній машині. Сценарії повинні мати можливість посилатися на шляхи відносно себе, тому мені потрібно мати можливість отримати шлях до файлу, який зараз виконується.

Мені відомо про dirname $0ідіому, яка прекрасно спрацьовує при прямому виклику мого сценарію. На жаль, є бажання мати можливість створювати посилання на ці сценарії з абсолютно іншого каталогу і все ще мати відносну логічну роботу.

Приклад загальної сухої структури такий:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

Як я можу надійно посилатися /usr/local/lib/foo/res/resource_file.txtз script.shтого , що викликається /usr/local/lib/foo/bin/script.shабо ~mike/bin/link_to_script?

Відповіді:


79

Спробуйте це як загальне рішення:

DIR="$(cd "$(dirname "$0")" && pwd)"

У конкретному випадку наступних посилань ви також можете це зробити:

DIR="$(dirname "$(readlink -f "$0")")"

Працює чудово і набагато простіше, ніж те, що я намагався. Дякую!
Майк Дек

@MikeDeck Насолоджуйтесь. Зауважте, що я виправив деякі проблеми із котируванням з моменту першої публікації ... ви можете скористатися опцією останнього редагування, якщо у вас на шляху колись є пробіли чи інші нерозумні символи. Навіть якщо це не має значення для цього проекту, ви можете скопіювати код із власних сценаріїв у дорозі, і тоді найкращий варіант має значення!
Калеб

1
Варто уточнити, другий працює чудово. Перше рішення, яке ви дали, не працює для посилань на моїй системі.
Майк Дек

4
@MikeDeck: Перше рішення працює для типового випадку наявності різних каталогів, позначених як частина шляху, але не допоможе, якщо кінцевим бінарним символом є посилання. Ось про що вдається подбати другий.
Калеб

1
Не працює, якщо файл сценарію sourced (наприклад $ source ./sript.sh) Це працює для обох випадків:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace

7

один рядок:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))

2
Відповіді на один рядок, як правило, не є найбільш корисними. Спробуйте розширити свою відповідь, щоб включити пояснення, посилання або документацію, які надалі підтримують запропоноване рішення.
HalosGhost

1
насправді, вам цього не потрібно, версія для читання посилань оригінальної відповіді працює чудово, якщо взагалі не задіяна символьна посилання
THESorcerer

3

readlink -f не працює для мене, я маю цю помилку:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

Але це прекрасно працює:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR


Так, я на MacOs @isaac, але у мене немає жодного питання. Я розмістив команду, яка працює на моєму боці.
Кевін Кемпіон

0

Одне невелике доповнення до вищезазначеного сценарію. Варіант -P до pwd слідує за посиланнями

DIR="$(cd "$(dirname "$0")" && pwd -P)"

7
Це працює лише тоді, коли симпосилання є частиною структури каталогу. Він не працює, коли сам файл пов'язаний.
Олівер Гонджа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.