RosettaCodeページで次のようなシバンを見つけました。
--() { :; }; exec db2 -txf "$0"
Db2でも機能し、Postgresでも同様です。しかし、私は全体の行を理解していません。
ダブルダッシュはSQLのコメントであり、その後、ファイル自体をファイルとして渡すいくつかのパラメーターを使用してDb2実行可能ファイルを呼び出します。しかし、括弧、中括弧、コロン、セミコロン、および実際のシバン#を置き換える方法はどうでしょうか。?
RosettaCodeページで次のようなシバンを見つけました。
--() { :; }; exec db2 -txf "$0"
Db2でも機能し、Postgresでも同様です。しかし、私は全体の行を理解していません。
ダブルダッシュはSQLのコメントであり、その後、ファイル自体をファイルとして渡すいくつかのパラメーターを使用してDb2実行可能ファイルを呼び出します。しかし、括弧、中括弧、コロン、セミコロン、および実際のシバン#を置き換える方法はどうでしょうか。?
回答:
関連:どのシェルインタープリターがシバンなしでスクリプトを実行しますか?
スクリプトにはshebang / hashbang /の#!
行がありません#!
。単に二重ダッシュがないためです。
ただし、スクリプトはシェルによって実行され(上記のリンクされた質問と回答を参照)、そのシェルで-
は、関数名に有効な文字がある場合、行--
は何もしないというシェル関数を宣言します(まあ、それは実行されます:
、whichは何もしません)、そして呼び出されません。
より一般的な複数行表記法の関数(その奇妙な名前が実際に関数であるという事実をちょっとわかりにくくするために、外観をより明確にするため):
-- () {
:
}
関数定義の唯一の目的は、シェルスクリプトで有効な行と、同時に有効なSQLコマンド(コメント)を持つことです。この種のコードはポリグロットと呼ばれます。
偽のシェル関数を宣言した後、スクリプトは、シェルスクリプトインタープリターによって実行されるとexec
、現在のシェルを実行中のプロセスに置き換えますdb2 -txf "$0"
。これはdb2 -txf
、コマンドラインからスクリプトのパス名を使用する場合と同じです。
このトリックは、おそらくdash
他のash
ベースのシェル、yash
Bourneシェル、ksh88
またはksh93
として使用されているシステムでは/bin/sh
、名前にダッシュが含まれる関数を受け入れないため、確実に機能しません。
関連:
以下も動作すると思います(実際にはテストされていません):
--() { exec db2 -txf "$0"; }; --
@Kusalanandaが既に言ったように、そのトリックは壊れており、すべてのシェルで機能するわけではありません。
これを移植性のある方法で紹介します。
--/.. 2>/dev/null; exec db2 -txf "$0"
という名前のファイル/ディレクトリ--
が現在のディレクトリに存在していても、最初のコマンドは失敗するはず2>/dev/null
です。エラーが発生すると、; 次に、シェルは2番目のコマンドであるexec
。
ENOEXEC
しようとすると戻るという事実を回避するために、呼び出しシェルに依存しています。スクリプトを実行して、strace
意味を確認してください。
exec()
しない場合、シェルはスクリプトをシェルスクリプトとして実行することになっています。「[ENOEXEC]エラーに相当するエラーのためにexecl()関数が失敗した場合、シェルは、コマンド名を最初のオペランドとしてシェルを起動するのと同等のコマンドを実行します...」(pubs.opengroupを参照.org / onlinepubs / 9699919799.2018edition / utilities /…)
exec()
シェル以外のものから直接アクセスすると動作しません。しかし、その場合はどうなりますか?スクリプトを実行したいかもしれませんが、cron
とにかくシェルを介してすべてを実行していると思いますdb2 -txf /path/to/script
。速記の作業は、対話型シェルで主に役立ちます。ただし、独立したラッパースクリプトの方が堅牢である可能性があります。
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