Як працює цей шебанг, який починається з подвійного дефісу (-)?


14

На сторінці RosettaCode я знайшов такий вид шебангу:

--() { :; }; exec db2 -txf "$0"

Він працює для Db2, і аналогічна річ для Postgres. Однак я не розумію цілу лінію.

Я знаю, що подвійний тире - це коментар у SQL, і після цього він викликає виконуваний файл Db2 з деякими параметрами, передаючи сам файл як файл. А як щодо дужок, фігурних дужок, товстої та напівкрапки та як можна замінити справжній шебанг #! ?

https://rosettacode.org/wiki/Multiline_shebang#PostgreSQL

Відповіді:


18

Пов'язані: Який інтерпретатор оболонки виконує сценарій без шебанга?

У сценарії немає шебанг / хешбанг /#! рядок, просто тому, що подвійний тире - ні #!.

Однак сценарій буде виконаний оболонкою (див. Вище пов'язане питання та відповіді), і в цій оболонці, якщо -є дійсним символом у назві функції, рядок оголошує функцію оболонки, яка називається, --що нічого не робить (ну, вона працює :, який нічого не робить ) і який ніколи не називається.

Функція, у більш поширених багаторядкових позначеннях (лише для того, щоб зробити більш очевидним, як вона виглядає, оскільки її незвичайна назва ніби затьмарює той факт, що вона насправді є функцією):

-- () {
  :
}

Єдиною метою визначення функції є наявність рядка, що є дійсним у сценарії оболонки, і в той же час дійсна команда SQL (коментар). Цей вид коду називається a поліглотом .

Після оголошення функції фальшивої оболонки сценарій, коли виконується інтерпретатором сценарію оболонки, використовує execдля заміни поточної оболонки процесом, що виникає в результаті запускуdb2 -txf "$0" , який би був таким самим, як і використання db2 -txfв імені шляху скрипту з командного рядка.

Цей трюк, ймовірно, не працює надійно в системах, де dashабо інші ashоболонки на основі, оболонки yashБорна, ksh88або ksh93використовуються як/bin/sh , оскільки ці оболонки не приймають функції, назва яких містить тире.

Також пов'язані:


Я припускаю, що також працює (не дуже перевірено):

--() { exec db2 -txf "$0"; }; --

@ilkkachu Краще зараз?
Кусалаланда

1
о, так! І дякую, що нагадали, як називається така штука. :)
ilkkachu

6

Як вже говорив @Kusalananda, цей трюк порушений, і він працюватиме не у всіх оболонках.

Ось мій досвід робити це портативно:

--/.. 2>/dev/null; exec db2 -txf "$0"

Перша команда повинна вийти з ладу, навіть якщо названий файл / каталог --існує в поточному каталозі, і помилки будуть закриті 2>/dev/null; Потім оболонка перейде до другої команди - exec.


Це все ще не дуже портативно. Це не допустимий сценарій, і ви все ще покладаєтесь на оболонку виклику, щоб обійти той факт, що ядро ​​відмовиться запускати сценарій і повернеться, ENOEXECякщо ви спробуєте це зробити. Спробуйте запустити сценарій внизу, straceщоб побачити, що я маю на увазі.
kasperd

@kasperd, він все одно повинен бути портативним, оболонка повинна запускати сценарій як сценарій оболонки, якщо exec()він не працює на ньому. "Якщо функція execl () виходить з ладу через помилку, еквівалентну помилці [ENOEXEC], оболонка повинна виконати команду, еквівалентну тому, щоб оболонка викликала ім'я команди як її першого операнда, ..." (див. Pubs.opengroup .org / onlinepubs / 9699919799.2018edition / комунальні послуги /… )
ilkkachu

@ilkkachu Але сценарії не завжди виконуються з оболонки. Якщо ви спробуєте використати скрипт у будь-якому іншому контексті, де виконується виконуваний файл, він вийде з ладу. Більше того, оболонки не погоджуються, якого перекладача використовувати. Тож ваш сценарій тепер буде вести себе по-різному або взагалі виходитиме з ладу, залежно від того, з якого контексту він викликаний.
kasperd

@kasperd, звичайно, це не спрацює, якщо ви будете exec()безпосередньо з чогось іншого, ніж оболонки. Але що це за випадок? Можливо, ви хочете запустити сценарій з cronтакого чи іншого, але я думаю, що він все одно працює через оболонку, і навіть якщо ні, db2 -txf /path/to/scriptу цьому випадку просто просто прописати , оскільки це потрібно зробити лише один раз. Робота зі скороченням роботи корисна для інтерактивної оболонки. Але, звичайно, окремий сценарій обгортки може бути більш надійним.
ilkkachu

1
@kasperd Я не буду дратувати вас документами та стандартами; просто спробуйте! echo 'int main(int c,char**a){execvp(a[1],a+1);}' | cc -include unistd.h -xc -; echo echo yeah > a.sh; chmod 755 a.sh; ./a.out ./a.sh; PATH=`pwd` ./a.out a.sh
Дядько Біллі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.