6

私はこれが間違っていることを知っています。perlがこれをどのように解析するか知りたいだけです。

それで、私はperlで遊んでいます、私が欲しかったのはperl -ne私がタイプしたものでしperl -ieた、行動はちょっと面白いものでした、そして私は何が起こったのか知りたいです。

$ echo 1 | perl -ie'next unless /g/i'

だから、その上でperl Aborted (core dumped)perl --help私が見る読書-iはバックアップのための拡張を取ります。

-i[extension]     edit <> files in place (makes backup if extension supplied)

知らない人にとって-eはただの評価です。だから私は、3つのことのうちの1つが起こった可能性があると考えています。

  1. perl -i -e'next unless /g/i' 私はundefを取得し、残りはeの引数として使用されます
  2. perl -ie 'next unless /g/i' 私は引数eを取得し、残りはファイル名のようにぶら下がっています
  3. perl -i"-e'next unless /g/i'" 私への議論としてのすべて

私が走るとき

$ echo 1 | perl -i -e'next unless /g/i'

プログラムは中止されません。'next unless /g/i'これは、それがへの文字通りの引数として解析されていないことを私に信じさせます-e。明らかに、上記はそのように解析され、異なる結果になります。

それで、それは何ですか?もう少し遊んで、私は得た

$ echo 1 | perl -ie'foo bar'
Unrecognized switch: -bar  (-h will show valid options).

$ echo 1 | perl -ie'foo w w w'
... works fine guess it reads it as `perl -ie'foo' -w -w -w`

上記をいじって、これを試してみます...

$ echo 1 | perl -ie'foo e eval q[warn "bar"]'
bar at (eval 1) line 1.

今、私は本当に混乱しています。では、Perlはこれをどのように解析しているのでしょうか。最後に、実際には。内からPerlevalコマンドを取得できるようです-i。これにはセキュリティ上の影響がありますか?

$ perl -i'foo e eval "warn q[bar]" '
4

2 に答える 2

7

素早い回答

シェルの見積もり処理は、すべて1つの引数であると考えているものを折りたたんで連結します。あなたの呼び出しは同等です

$ perl '-ienext unless /g/i'

perlはこの引数を含むものとして解析するため、すぐに中止され-uます。これにより、コードの実行が開始されるコアダンプがトリガーされます。これは、かつて疑似実行可能ファイルを作成するために使用されていた古い機能ですが、最近では本質的に痕跡的です。

の呼び出しのように見えるevalのは、の誤解析です-e 'ss /g/i'

最初の手がかり

B ::サポートなしでシステムを実行している場合は、友達を解凍できますdump

$ echo 1 | perl -MO=Deparse,-p -ie'next unless /g/i'
dump is not supported.
BEGIN { $^I = "enext"; }
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined(($_ = <ARGV>))) {
    chomp($_);
    (('ss' / 'g') / 'i');
}

では、なぜunle消えるのですか?Linuxを実行している場合は、私が行ったほどには到達していない可能性があります。上記の出力はCygwin上のPerlからのものであり、dumpサポートされていないことに関するエラーが手がかりです。

次の手がかり

perlrunのドキュメントからの注目:

-u

このスイッチにより、プログラムのコンパイル後にPerlがコアダンプします。次に、理論的には、このコアダンプを取得し、アンダンププログラム(提供されていません)を使用して実行可能ファイルに変換できます。これにより、ディスク容量をいくらか犠牲にして起動が高速化されます(実行可能ファイルを削除することで最小限に抑えることができます)。(それでも、「helloworld」実行可能ファイルは私のマシンでは約200Kになります。)ダンプする前にプログラムの一部を実行する場合は、dump代わりに演算子を使用してください。注:アンダンプの可用性はプラットフォーム固有であり、Perlの特定のポートでは利用できない場合があります。

作業仮説と確認

Perlの引数処理では、チャンク全体がダッシュで始まるため、オプションの単一クラスターと見なされます。処理の実装でわかるように、この-iオプションは次の単語()を消費します。enext-i

case 'i':
    Safefree(PL_inplace);
    [Cygwin-specific code elided -geb]
    {
        const char * const start = ++s;
        while (*s && !isSPACE(*s))
            ++s;

        PL_inplace = savepvn(start, s - start);
    }
    if (*s) {
        ++s;
        if (*s == '-')      /* Additional switches on #! line. */
            s++;
    }
    return s;

バックアップファイルの拡張子については、上記のperl.cのコードは、最初の空白文字または文字列の終わりのいずれか早い方までを消費します。文字が残っている場合は、最初の文字を空白にしてからスキップし、次の文字がダッシュの場合もスキップします。Perlでは、このロジックを次のように記述できます。

if ($$s =~ s/i(\S+)(?:\s-)//) {
  my $extension = $1;
  return $extension;
}

次に、、、、およびのすべて-uが有効-nなPerlオプションであるため、引数処理はそれらを食べて無意味なままにします-l-e

ss /g/i

の引数として、-eperlは一連の除算として解析します。しかし、実行が始まる前に、古語法-uはperlにコアダンプを引き起こします。

意図しない動作

さらに奇妙なのは、との間に2つのスペースを入れる場合ですnextunless

$ perl -ie'next  unless /g/i'

プログラムは実行を試みます。メインのオプション処理ループに戻ります。

case '*':
case ' ':
    while( *s == ' ' )
      ++s;
    if (s[0] == '-')        /* Additional switches on #! line. */
        return s+1;
    break;

余分なスペースは、その引数のオプション解析を終了します。目撃者:

$ perl-ie'次のナンセンス-garbage--foo'-e die
-e行1で死亡しました。

しかし、余分なスペースがなければ、

$ perl-ie'次のナンセンス-garbage--foo'-e die
認識されないスイッチ:-onsense -garbage --foo(-hは有効なオプションを表示します)。

ただし、余分なスペースとダッシュがあります

$ perl -ie'next -unless / g / i'
ダンプはサポートされていません。

デザインの動機

コメントが示すように、ロジックは厳しいシバン(#!)行制約のためにあり、perlは回避するために最善を尽くします。

インタプリタスクリプト

インタプリタスクリプトは、実行権限が有効になっていて、最初の行が次の形式のテキストファイルです。

#! interpreter [optional-arg]

インタプリタは、それ自体がスクリプトではない実行可能ファイルの有効なパス名である必要があります。のfilename引数がexecveインタプリタスクリプトを指定している場合、インタプリタは次の引数で呼び出されます。

interpreter [optional-arg] filename arg...

ここで、arg ...は、。のargv引数が指す一連の単語ですexecve

ポータブルで使用する場合、optional-argは存在しないか、単一の単語として指定する必要があります(つまり、空白を含めることはできません)…</ p>

于 2012-05-22T20:27:06.353 に答える
5

知っておくべき3つのこと:

  1. '-x y'Perlを意味-xyします(いくつかの任意のオプション「x」および「y」の場合)。

  2. -xy、UNIXツールで一般的なのは、を表す「バンドル」-x -yです。

  3. -i、のよう-eに引数の残りを吸収します。とは異なり-e、スペースは引数の終わりであると見なされます(上記の#1のとおり)。

つまり、

-ie'next unless /g/i'

これはただの派手な書き方です

'-ienext unless /g/i'

にバンドルを解除します

-ienext -u -n -l '-ess /g/i'
  ^^^^^             ^^^^^^^
----------         ----------
val for -i         val for -e

perlrunドキュメント-u

このスイッチにより、プログラムのコンパイル後にPerlがコアダンプします。次に、理論的には、このコアダンプを取得し、アンダンププログラム(提供されていません)を使用して実行可能ファイルに変換できます。これにより、ディスク容量をいくらか犠牲にして起動が高速化されます(実行可能ファイルを削除することで最小限に抑えることができます)。(それでも、「helloworld」実行可能ファイルは私のマシンでは約200Kになります。)ダンプする前にプログラムの一部を実行する場合は、代わりにdump()演算子を使用してください。注:アンダンプの可用性はプラットフォーム固有であり、Perlの特定のポートでは利用できない場合があります。
于 2012-05-22T21:03:49.680 に答える