Shebang

Vadym Kykalo · May 29, 2022

Шебанг

shebang_logo

Для прикладу, створимо файл із розширенням .php, та напишемо програму яка виводить в термінал теперішню дату.

$ echo "<?php print date(\"D M j G:i:s T Y\") . \"\n\";" > pdate.php

Команда echo виводить текст на стандартний пристрій виводу в stdout, зазвичай це термінал, але через опцію > ми перенаправляємо stdout echo в stdin файлу pdate.php.

Якщо встановлений інтерпретатор php, запустити програму можна так:

$ php pdate.php 
Sun May 29 19:12:41 EEST 2022

Програму можна оптимізувати, постійно вказувати інтерпретатор(програма виконання) і шлях до файлу злегка роздратовує, тому спочатку дізнаємось де знаходиться інтерпретатор php:

$ which php
/usr/bin/php

Команда which використовується для пошуку виконуваних файлів та показує шлях, де знаходиться вказаний файл на файловій системі.

Додамо #!/usr/bin/php в першому рядку файлу pdate.php, після цього файл виглядає:

$ cat pdate.php 
#!/usr/bin/php
<?php print date("D M j G:i:s T Y") . "\n";

Запускаємо скрипт як винонуваний файл:

$ ./pdate.php
bash: ./pdate.php: Permission denied

Хм…. відмовлено в доступі.. Перевіримо права

$ ls -l ./pdate.php 
-rw-rw-r-- 1 vkykalo vkykalo 59 мая 29 19:33 ./pdate.php

Бачимо, що файл pdate.php не є виконувальним тому ./pdate.php не запрацює, тому зробимо наступне:

$ chmod a+x pdate.php

Цей додатковий крок означає наступне, “комп’ютер, зроби мій файл pdate.php виконувальним” і запустимо ще раз файл ./pdate.php

$ ./pdate.php 
Sun May 29 21:04:01 EEST 2022

Працює, для лаконічності приберемо зайве розширення файлу .php

$ mv pdate.php pdate

Запускаємо програму як винувальний файл ./pdate

$ ./pdate 
Sun May 29 21:16:49 EEST 2022

Насправді ми ніякої функціональності не додали в нашу програму, проте більше не потрібно вказувати виконавчу програму для запуску скрипту, за нас зробив це Шебанг.

Зробимо ще одну оптимізацію, замінимо шебанг #!/usr/bin/php на #!/usr/bin/env php, щоб програма мала наступний текст файлу:

$ cat pdate 
#!/usr/bin/env php
<?php print date("D M j G:i:s T Y") . "\n";

Фактично, нічого не змінилося. Проте питання, для чого були зміни?

Основна ідея – це кросплатформеність. Не має гарантії, що на різних unix системах, програми, що виконуються, будуть лежати по шляху, який вказаний в shebang. Іншими словами, на різних дистрибутивах linux шлях до інтерпретатора php може бути різний, а утиліта /usr/bin/env займається пошуком виконувальних програм.

Використання env дозволяє знизити цей ризик за рахунок запуску команди, на основі даних зі змінною середовища $PATH. Утиліті /usr/bin/env передаємо ту утиліту яку хочемо запустити (php, python2, python3…) і вона сама знайде і запустить необхідну версію вам інтерпретатора.

Шлях до php інтерпретатора не на всіх дистрибутивах linux буде мати /usr/bin/php.

Шебанг(#!) - це просто шлях до програми в типовій unix системі, яка має назву середовище.

Перший рядок просто нам говорить, є #!/usr/bin/env php, знайди мені php інтерпретатор у своєму середовищі env та запусти файл.

Відтепер для користувача цієї програми не буде важливо знати, а на якій мові програмування написаний скрипт.

Приклад на python3

$ echo "print('hello world')" > test.py
$ python3 test.py 
hello world

Додаємо шебанг #!/usr/bin/env python3 та змінюємо режим chmod a+x test.py і робимо ренейм mv test.py test

Після цього робимо запуск

$ ./test 
hello world

Створюємо власну утиліту

Більшість команд, які ми використовуємо в терміналі(pwd, ls, cat, rm, cp, echo…) знаходяться в каталозі /usr/bin/, проте не тільки там знаходяться виконувальні програми.

Коли ми набираємо будь-яку команду в терміналі, linux перевіряє змінну середовища $PATH, в якій знаходяться каталоги в яких необхідно здійснити пошук до виконувальної команди.

$ echo $PATH
/home/vkykalo/.nvm/versions/node/v10.24.1/bin:/home/vkykalo/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Якщо ми хочемо написати власну утиліту, її необхідно перемістити в одну із каталогів, але кращою практикою для цього являється каталог ~/.local/bin, або ~/.bashrc

Зробимо нашу програму pdate глобальною утилітою як інші команди (ls,echo..).

Нагадаємо код програми та права на файл.

vkykalo@vkykalo-HP-ProBook-455R-G6:~$ ls -la pdate 
-rwxrwxr-x 1 vkykalo vkykalo 63 июн  7 23:57 pdate
vkykalo@vkykalo-HP-ProBook-455R-G6:~$ cat pdate 
#!/usr/bin/env php
<?php print date("D M j G:i:s T Y") . "\n";

Переносимо файл

$ mv pdate ~/.local/bin

Ось і все! Можемо користуватися командою pdate.

vkykalo@vkykalo-HP-ProBook-455R-G6:~/workspace/github$ pdate 
Wed Jun 8 0:04:22 EEST 2022
vkykalo@vkykalo-HP-ProBook-455R-G6:~/workspace/github$ ls
aws-lambda-python  Browser.java  index.php  pdf-JODConverter  static-blog-page  test.php

pdate файлу немає в каталозі, проте все працює.


Висновок

shebang економить наш час тим, що пишемо менше boilerplate code, також можемо створювати власні утиліти.

Посилання

Twitter, Facebook