ダブルハイフン(-)で始まるこのシバンはどのように機能しますか?


14

RosettaCodeページで次のようなシバンを見つけました。

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

Db2でも機能し、Postgresでも同様です。しかし、私は全体の行を理解していません。

ダブルダッシュはSQLのコメントであり、その後、ファイル自体をファイルとして渡すいくつかのパラメーターを使用してDb2実行可能ファイルを呼び出します。しかし、括弧、中括弧、コロン、セミコロン、および実際のシバン#を置き換える方法はどうでしょうか。?

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

回答:


18

関連:どのシェルインタープリターがシバンなしでスクリプトを実行しますか?

スクリプトにはshebang / hashbang /の#!行がありません#!。単に二重ダッシュがないためです。

ただし、スクリプトはシェルによって実行され(上記のリンクされた質問と回答を参照)、そのシェルで-は、関数名に有効な文字がある場合、行--は何もしないというシェル関数を宣言します(まあ、それは実行されます:whichは何もしません)、そして呼び出されません。

より一般的な複数行表記法の関数(その奇妙な名前が実際に関数であるという事実をちょっとわかりにくくするために、外観をより明確にするため):

-- () {
  :
}

関数定義の唯一の目的は、シェルスクリプトで有効な行と、同時に有効なSQLコマンド(コメント)を持つことです。この種のコードはポリグロットと呼ばれます。

偽のシェル関数を宣言した後、スクリプトは、シェルスクリプトインタープリターによって実行されるとexec、現在のシェルを実行中のプロセスに置き換えますdb2 -txf "$0"。これはdb2 -txf、コマンドラインからスクリプトのパス名を使用する場合と同じです。

このトリックは、おそらくdash他のashベースのシェル、yashBourneシェル、ksh88またはksh93として使用されているシステムでは/bin/sh、名前にダッシュが含まれる関数を受け入れないため、確実に機能しません。

関連:


以下も動作すると思います(実際にはテストされていません):

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

@ilkkachuより良いですか?
クサラナナンダ

1
そうそう!そして、そのようなものが何と呼ばれているのか思い出させてくれてありがとう。:)
ilkkachu

6

@Kusalanandaが既に言ったように、そのトリックは壊れており、すべてのシェルで機能するわけではありません。

これを移植性のある方法で紹介します。

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

という名前のファイル/ディレクトリ--が現在のディレクトリに存在していても、最初のコマンドは失敗するはず2>/dev/nullです。エラーが発生すると、; 次に、シェルは2番目のコマンドであるexec


まだ実際には移植性がありません。これは有効なスクリプトではなく、カーネルがスクリプトの実行を拒否し、実行ENOEXECしようとすると戻るという事実を回避するために、呼び出しシェルに依存しています。スクリプトを実行して、strace意味を確認してください。
カスペルド

@kasperd、それはまだ移植可能でなければなりません、それで動作exec()しない場合、シェルはスクリプトをシェルスクリプトとして実行することになっています。「[ENOEXEC]エラーに相当するエラーのためにexecl()関数が失敗した場合、シェルは、コマンド名を最初のオペランドとしてシェルを起動するのと同等のコマンドを実行します...」pubs.opengroupを参照.org / onlinepubs / 9699919799.2018edition / utilities /…
ilkkachu

@ilkkachuしかし、スクリプトは常にシェルから実行されるとは限りません。実行可能ファイルが機能する他のコンテキストでスクリプトを使用しようとすると、失敗します。さらに、シェルはどのインタープリターを使用するかについて同意しません。そのため、スクリプトはどのコンテキストから呼び出されているかに応じて、異なる動作をするか、完全に失敗します。
カスペルド

@kasperd、まあ、確かに、exec()シェル以外のものから直接アクセスすると動作しません。しかし、その場合はどうなりますか?スクリプトを実行したいかもしれませんが、cronとにかくシェルを介してすべてを実行していると思いますdb2 -txf /path/to/script。速記の作業は、対話型シェルで主に役立ちます。ただし、独立したラッパースクリプトの方が堅牢である可能性があります。
イルカチュウ

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
ビリーおじさん
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.