web-dev-qa-db-ja.com

シバン(すなわち#!)でawkに複数の引数を使用する方法は?

Shebangを使用して--re-intervalgawk スクリプトを実行したいと思います。 「ナイーブ」アプローチ

#!/usr/bin/gawk --re-interval -f
... awk script goes here

gawkは最初の引数"--re-interval -f"(空白の周りで分割されていない)で呼び出されるため、動作しません。これは理解できません。そのための回避策はありますか?

もちろん、直接gawkを呼び出すのではなく、最初の引数を分割するシェルスクリプトにラップするか、gawkを呼び出してスクリプトを別のファイルに入れるシェルスクリプトを作成することはできませんが、どうすればよいか疑問に思いましたこれは1つのファイル内にあります。

シバン行の動作はシステムによって異なります-少なくとも Cygwin では、引数を空白で分割しません。私はそのように振る舞うシステムでそれをどうやってやるのか気にしています。スクリプトは移植可能であることを意図していません。

112

これは(g)awkでうまくいくようです。

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"


# The real awk program starts here
{ print $0 }

#!/bin/shを実行することに注意してください。したがって、このスクリプトは最初にシェルスクリプトとして解釈されます。

最初は"exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"を試しましたが、awkはそれをコマンドとして扱い、入力のすべての行を無条件に出力しました。それが私がarbitrary_long_name==0を入れた理由です-常に失敗するはずです。あなたはいくつかの意味不明な文字列に置き換えることができます。基本的に、シェルスクリプトに悪影響を与えないawkの偽条件を探していました。

シェルスクリプトでは、arbitrary_long_name==0arbitrary_long_nameという変数を定義し、=0と等しく設定します。

23
Aaron McDaid

Shebangラインは、POSIX、SUS、LSBまたはその他の仕様の一部として指定されたことはありません。知る限りでは、適切に文書化されていません。

それが何をするかについて大まかなコンセンサスがあります:!\nexec itの間のすべてを取る。仮定は、!\nの間のすべてがインタープリターへの完全な絶対パスであるということです。空白が含まれている場合に何が起こるかについてのコンセンサスはありません。

  1. 一部のオペレーティングシステムは、単純に全体をパスとして扱います。結局のところ、ほとんどのオペレーティングシステムでは、空白文字またはダッシュはパスで有効です。
  2. 一部のオペレーティングシステムは空白で分割され、最初の部分をインタープリターへのパスとして扱い、残りを個別の引数として扱います。
  3. 一部のオペレーティングシステムはfirst空白で分割され、フロントパートをインターピーターへのパスとして扱い、残りをsingle引数(これが見ているもの)として扱います。
  4. シェバン行をサポートしていないものもありますまったく

ありがたいことに、1と4は消滅したように見えますが、3はかなり普及しているため、複数の引数を渡すことができることに頼ることはできません。

また、コマンドの場所もPOSIXまたはSUSで指定されていないため、通常、実行可能ファイルのnameenvに渡すことにより、その単一の引数を使い果たし、it =実行可能ファイルの場所を特定できます。例えば。:

#!/usr/bin/env gawk

[明らかに、このstillenvの特定のパスを想定していますが、/binにあるシステムは非常に少ないため、これは一般に安全です。 envの場所は、gawkの場所よりもはるかに標準化されているか、さらに悪いことにpythonRubyまたはspidermonkeyのようなものです。 ]

つまり、実際にはany引数すべてを使用することはできません。

153
Jörg W Mittag

同じ問題に出くわしましたが、シバンでの空白の処理方法(少なくともLinuxでは)のため、明確な解決策はありませんでした。

ただし、short optionsであり、かつconcatenated(GNU way )。

たとえば、あなたが持つことはできません

#!/usr/bin/foo -i -f

しかし、あなたは持つことができます

#!/usr/bin/foo -if

明らかに、これはオプションに短い同等物があり、引数を取らない場合にのみ機能します。

12
ℝaphink

CygwinとLinuxでは、シバンのパスの後のすべてが1つの引数としてプログラムに解析されます。

Shebang内で別のawkスクリプトを使用して、これを回避することができます。

_#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
_

これにより、awkで{system("/usr/bin/gawk --re-interval -f " FILENAME); exit}が実行されます。
そして、これはシステムのシェルで_/usr/bin/gawk --re-interval -f path/to/your/script.awk_を実行します。

12
Moritz

厳密には移植性はありませんが、coreutils 8.30および そのドキュメントによる から開始して、以下を使用できます。

#!/usr/bin/env -S command arg1 arg2 ...

与えられた:

$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too

あなたが取得します:

% ./test.sh 
$0 is '/usr/local/bin/showargs'
$1 is 'here'
$2 is 'is another'
$3 is 'long'
$4 is 'arg'
$5 is '-e'
$6 is 'this and that '
$7 is 'too'
$8 is './test.sh'

興味がある場合は、showargsは次のとおりです。

#!/usr/bin/env sh
echo "\$0 is '$0'"

i=1
for arg in "$@"; do
    echo "\$$i is '$arg'"
    i=$((i+1))
done

元の答え ここ

9
unode
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''

上記のシェルシバントリックは、/usr/bin/env

5
user3123730

Gawkマニュアル(http://www.gnu.org/manual/gawk/gawk.html)では、セクション1.14の最後に、Shbangラインからgawkを実行するときに単一の引数のみを使用する必要があることに注意してください。 OSはgawkへのパスの後のすべてを単一の引数として扱うと言っています。おそらく--re-intervalオプションを指定する別の方法がありますか?おそらく、スクリプトはShebang行でシェルを参照し、gawkをコマンドとして実行し、スクリプトのテキストを "here document"として含めることができます。

3
bta

なぜbashgawk自体を使用して、過去のShebangをスキップし、スクリプトを読み、それをファイルとしてgawk [--with-whatever-number-of-params-you-need]の2番目のインスタンスに渡すのですか?

#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' $0 )
exit
{
  print "Program body goes here"
  print $1
}

(-sedtailなどでも同様に実現できますが、bashgawk自体のみに依存する美しさがあると思います;)

3
conny

楽しみのために:ファイル記述子3と4を介してstdinとプログラムを再ルーティングする次の非常に奇妙なソリューションがあります。スクリプト用の一時ファイルを作成することもできます。

#!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print "HALLO"}
{print \$1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3

1つ問題があるのは、シェルがスクリプトで変数展開を行うため、$(スクリプトの2行目で行われているように)を引用する必要があるためです。

0