Як розділити змінну $ 0, щоб знайти каталог і відносні шляхи в bash?


10

Змінна $ 0 містить інформацію про шлях сценарію.

  • Як я можу змінити інформацію про шлях до абсолютного шляху? Я маю на увазі, як обробити ~,., .. чи подібне?
  • Як я можу розділити інформацію про шлях на ім'я каталогу та файлу?

Я можу використовувати python / perl для цього, але я хочу використовувати bash, якщо це можливо.


чого ви намагаєтесь досягти? btw. виклик сценарію з ~ / foo.sh розшириться ~ в мою домашню каталог за $ 0 за допомогою моєї версії bash (GNU bash, версія 4.1.5 (2) -release- (x86_64-unknown-linux-gnu))
echox

Відповіді:


17

Вам не потрібно обробляти такі речі, як ~оболонка робить це за вас. Ось чому ви можете перейти ~/filenameдо будь-якого сценарію чи програми, і це працює - всі ці програми не справляються ~самі, ваша оболонка перетворює аргумент /home/username/filenameі передає це програмі натомість:

$ echo ~/filename
/home/mrozekma/filename

Якщо вам потрібно канонічне ім’я файлу (яке не включає такі речі, як ..), використовуйте realpath(дякую Ніл ):

$ realpath ~/../filename
/home/filename

Що стосується розділення шляху на ім'я каталогу та ім'я файлу, використовуйте dirnameта basename:

$ dirname /foo/bar/baz
/foo/bar

$ basename /foo/bar/baz
baz

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

@Neil realpathкраще, але, readlinkздається, працює, коли я спробую це; чи знаєте ви приклад, коли він не вдається?
Майкл Мрозек

1
cd /tmp; touch foo; ln -s foo bar; cd; readlink /tmp/bar. Це повертається fooі realpathповертається /tmp/foo, що ви хочете.
Ніл Мейхью

1
@Neil, @Michael: readlink -f(замітка -f) майже еквівалентний realpath, і він більш портативний: readlink -fв GNU coreutils існує і в кількох інших системах; realpathупаковується окремо і не може бути встановлений (наприклад, лише 5 не звичайних пакетів залежать від нього в Ubuntu 10.04 або Debian lenny).
Жил "ТАК - перестань бути злим"

@Gilles: хороший момент. Дякуємо за нагадування про realpath -f.
Ніл Мейхев

5

Використання dirname та базового імені, як згадував Майкл, має бути найбезпечнішим способом отримати те, що ви хочете.

У будь-якому випадку, якщо ви дійсно хочете зробити це за допомогою "інструментів лише для удару", ви можете використовувати підстановку параметрів:

echo `basename $PWD`        # Basename of current working directory.
echo "${PWD##*/}"           # Basename of current working directory.
echo
echo `basename $0`          # Name of script.
echo $0                     # Name of script.
echo "${0##*/}"             # Name of script.
echo
filename=test.data
echo "${filename##*.}"      # data
                            # Extension of filename.

Цей приклад безпосередньо взято з Додаткового посібника з написання сценаріїв, який варто переглянути.

Пояснення досить просте:

$ {var # Pattern} Вилучіть з $ var найкоротшу частину $ Pattern, що відповідає передній частині $ var. $ {var ## Pattern} Вилучіть з $ var найдовшу частину $ Pattern, що відповідає передньому краю $ var.

Подивіться на малюнок , як деякі регулярні вирази і тому #або ##в який - то жадібної / не жадібний модифікатора.

Це може стати в нагоді, якщо вам доведеться зробити кілька складніших добуток частини контуру.


5
Остерігайтеся при використанні ${...##...}і друзів , а не dirnameта , basenameщо вони не працюють в усіх випадках. Наприклад, обидва ${0##*/}і ${0%/*}розгорніть до того самого, як $0якщо б $0він не містить /.
Жил "ТАК - перестань бути злим"

@Gilles Я розумію, чому ${0%/*}це не є хорошою альтернативою dirname. Однак, що не так з використанням ${0##*/}замість basename?
токсалот

@toxalot У цьому випадку єдиною проблемою є те, коли $0це ім'я каталогу з останньою /. Але я шкодую про свою пораду, бо dirnameкращого не виходить.
Жил "ТАК - перестань бути злим"

2

realpath це команда, яка повідомляє вам реальний шлях (видаляє .. та символічні посилання тощо)

Це стандартно з FreeBSD. Відповідно до цієї дискусії, вона також доступна для Linux:

http://www.unix.com/shell-programming-scripting/89294-geting-real-path.html

Ця дискусія також пропонує баш-рішення:

$ bash -c "cd /foo/../bar/ ; pwd"

1
Саме так зазвичай працює: MYDIR = "$ (cd $ (dirname" $ ​​0 "); pwd)"
Кевін Канту
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.