Я сравнил многие из приведенных ответов и нашел несколько более компактных решений. Похоже, они справляются со всеми безумными крайними случаями, возникающими из вашей любимой комбинации:
- Абсолютные пути или относительные пути
- Программные ссылки для файлов и каталогов
- Вызывается как
script
, bash script
, bash -c script
, source script
или . script
- Пробелы, вкладки, переводы строк, юникод и т. Д. В каталогах и / или именах файлов
- Имена файлов, начинающиеся с дефиса
Если вы работаете в Linux, кажется, что использование дескриптора proc
является лучшим решением для поиска полностью разрешенного источника запущенного в данный момент сценария (в интерактивном сеансе ссылка указывает на соответствующий /dev/pts/X
):
resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"
Это немного уродливо, но исправление компактно и легко для понимания. Мы не используем только примитивы bash, но я согласен с этим, потому что readlink
значительно упрощает задачу. echo X
добавляет X
в конец строки переменной, так что любые конечные пробелы в имени файла не съедаются, а подстановка параметра ${VAR%X}
в конце строки избавляет от X
, Поскольку readlink
добавляет собственную новую строку (которая обычно используется в подстановке команд, если бы не наш предыдущий обман), мы также должны избавиться от этого. Этого легче всего достичь, используя схему цитирования $''
, которая позволяет нам использовать escape-последовательности, такие как \n
, для представления новых строк (это также то, как вы можете легко создавать каталоги и файлы с коварными именами).
Вышеуказанное должно охватывать ваши потребности в поиске текущего запущенного скрипта в Linux, но если у вас нет файловой системы proc
в вашем распоряжении или вы пытаетесь найти полностью разрешенный путь какого-либо другого файла , то, возможно, вы найдете следующий код полезным. Это всего лишь небольшая модификация вышеупомянутой однострочной. Если вы играете со странными каталогами / именами файлов, проверка вывода с помощью ls
и readlink
является информативной, так как ls
выведет «упрощенные» пути, заменяя ?
такими вещами, как переводы строк.
absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}
ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"