実験と例

実験と例

コメントからこの問題さまざまなsed実装がかなり単純なプログラムについて意見が一致しない状況が発生し、私たち(または少なくとも私は)仕様が実際にこれを求めているものを決定することはできません。

問題は、削除された行から始まる範囲の動作です。

1d;1,2d

2行目を削除する必要がありますか?コマンドに到達する前に範囲の先頭が削除されたにもかかわらず?私の初期の期待はBSD sedと一致する「いいえ」でしたが、GNU sedは「はい」と答えましたが、仕様テキストをチェックしても問題は完全に解決されませんでした。

(少なくとも)私の期待を満たすことはmacOSとSolarissedとBSDですsed。 GNUとBusybox(少なくとも)sedそしてここの多くは同意しません。最初の2つはSUS認証を受けていますが、他のものはより広範囲になる可能性があります。どんな行動が正しいですか?


これ規範的なテキスト2つのアドレス範囲について教えてください。

これsedその後、ユーティリティは、コマンドが次のサイクルを開始または終了するまで、アドレスがそのパターンスペースを順番に選択するすべてのコマンドを適用する必要があります。

そして

2つのアドレスを持つ編集コマンドは、最初のアドレスと一致する最初のパターンスペースから2番目のアドレスと一致する次のパターンスペースまで、包含範囲を選択する必要があります。 [...] 選択した範囲の後の最初の行から始まり、sed は最初のアドレスを再検索します。その後、このプロセスを繰り返す必要があります。

2号線と言えます。はい 以内に開始点が削除されたか否かに関わらず、「第1のアドレスに一致する第1のパターン空間から第2のアドレスに一致する次のパターン空間までの包含範囲」である。一方、最初のサイクルは、d範囲に開始する機会を与えずに次のサイクルに入ることが期待されます。 UNIX™認証の実装は私の期待を満たしていますが、仕様要件を満たしていない可能性があります。

以下はいくつかの例示的な実験ですが、重要な質問は次のとおりです。しなければならない sed削除された行から範囲が始まるとどうなりますか?


実験と例

問題の簡略化されたデモは次のとおりです。これにより、行を削除する代わりに追加のコピーが印刷されます。

printf 'a\nb\n' | sed -e '1d;1,2p'

これはsed2行の入力をa提供しますb。このプログラムは2つのことを行います。

  1. 最初の行を削除します1ddコマンド〜する

    パターン空間を削除し、次のループを開始します。そして

  2. 各行に受信した内容を自動的に印刷するほか、1~2行の範囲を選択して明示的に印刷することが可能です。したがって、この範囲内に含まれる行は2回表示される必要があります。

私の期待は、これを印刷する必要があるということです

b

1,2ただし、行1では範囲に達していないため(すでに次の期間/行にジャンプしているため)、範囲は適用されないため、削除されている間は範囲の埋め込みがd開始されません。通常、aSolaris および BSD のsed非 POSIX と同様に、macOS および Solaris 10 で Unix に準拠すると、この出力が生成されます。sedsed

一方、GNU sedは印刷します。

b
b

見せる持つ範囲を説明しました。これは、POSIX モードと非 POSIX モードの両方で発生します。 Busyboxのsedも同じ動作をします(ただし、動作が必ずしも同じではないため、共有コードの結果ではないようです)。

さらなる実験

printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/c/p'
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/d/p'

削除された行から始まる範囲を次のように処理することがわかりました。次のようなワイヤー。これは/c/、終了範囲と不一致があるために表示されます。/b/実際に範囲を開始するために使用いいえ動作はと同じです2


私が使用した最初の作業の例は次のとおりです。

printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'

最初の行にあっても、最初の一致の/a/前にすべての行を削除する方法です(GNU sedが実行するアクション0,/a/d- これはPOSIX準拠の変換を試みたものです)。

このアイテムはできるだけ削除する必要があることが示唆されました。第二最初の行が一致する場合(または2行目が一致しない場合はファイル全体)、/a/これは適切に見えますが、GNU sedだけがこれを実行します。 macOS sed と Solaris sed の両方が作成されます。

b
c
d
e

これは期待どおりに機能します(GNU sedは終了していない範囲を削除して空の出力を生成します。Busybox sedはdsumのみを印刷しますが、eとにかく間違っています)。一般的に言えば、私は彼らが認証適合性テストに合格したという事実が彼らが正しく行動することを意味すると仮定します。しかし、多くの人が私が確信していないと提案しており、仕様書は完全に説得力がなく、テストスイートもそうではありません。非常に包括的です。

明らかに、今日このコードを書くことは不一致のために実際に移植可能ではありませんが、理論的にそれはどこでもいろいろな意味を持つべきです。私はこれがバグだと思いますが、どの実装について報告するべきかわかりません。現在の私の見解は、GNUとBusybox sedが仕様と一貫していないように動作することです。しかし、私は間違っているかもしれません。

POSIXには何が必要ですか?

ベストアンサー1

この質問は2012年3月にオースティングループメーリングリストに提出されました。この問題の最後の言葉は次のとおりです(この問題を最初に提起したAustinグループ(POSIXを維持する組織)のGeoff Clareが提起しました)。以下はgmane NNTPインターフェイスからコピーされました。

Date: Fri, 16 Mar 2012 17:09:42 +0000
From: Geoff Clare <gwc-7882/[email protected]>
To: austin-group-l-7882/[email protected]
Newsgroups: gmane.comp.standards.posix.austin.general
Subject: Re: Strange addressing issue in sed

Stephane Chazelas <[email protected]> wrote, on 16 Mar 2012:
>
> 2012-03-16 15:44:35 +0000, Geoff Clare:
> > I've been alerted to an odd behaviour of sed on certified UNIX
> > systems that doesn't seem to match the requirements of the
> > standard.  It concerns an interaction between the 'n' command
> > and address matching.
> > 
> > According to the standard, this command:
> > 
> > printf 'A\nB\nC\nD\n' | sed '1,3s/A/B/;1,3n;1,3s/B/C/'
> > 
> > should produce the output:
> > 
> > B
> > C
> > C
> > D
> > 
> > GNU sed does produce this, but certified UNIX systems produce this:
> > 
> > B
> > B
> > C
> > D
> > 
> > However, if I change the 1,3s/B/C/ to 2,3s/B/C/ then they produce
> > the expected output (tested on Solaris and HP-UX).
> > 
> > Is this just an obscure bug from common ancestor code, or is there
> > some legitimate reason why this address change alters the behaviour?
> [...]
> 
> I suppose the idea is that for the second 1,3cmd, line "1" has
> not been seen, so the 1,3 range is not entered.

Ah yes, now it makes sense, and it looks like the standard does
require this slightly strange behaviour, given how the processing
of the "two addresses" case is specified:

    An editing command with two addresses shall select the inclusive
    range from the first pattern space that matches the first address
    through the next pattern space that matches the second.  (If the
    second address is a number less than or equal to the line number
    first selected, only one line shall be selected.) Starting at the
    first line following the selected range, sed shall look again for
    the first address. Thereafter, the process shall be repeated.

It's specified this way because the addresses can be BREs, but if
the same matching process is applied to the line numbers (even though
they can only match at most once), then the 1,3 range on that last
command is never entered.

-- 
Geoff Clare <g.clare-7882/[email protected]>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England

Jeffが(私から)引用したメッセージの残りの部分の関連部分は次のとおりです。

I suppose the idea is that for the second 1,3cmd, line "1" has
not been seen, so the 1,3 range is not entered.

Same idea as in

printf '%s\n' A B C | sed -n '1d;1,2p'

whose behavior differ in traditional (heirloom toolchest at
least) and GNU.

It's unclear to me whether POSIX wants one behavior or the
other.

したがって(Geoffによると)POSIXは明らかGNUは違法に行動します。

実際には、一貫性が少ないseq 10 | sed -n '1d;1,2p'seq 10 | sed -n '1d;/^1$/,2p'「奇妙な」)。

誰もこれをGNUの人々にバグとして報告したくありません。これをバグだと思うべきかわかりません。おそらく最良の選択は、両方の動作を許可するようにPOSIX仕様を更新して、どちらにも依存できないことを明らかにすることです。

編集する。 1970年代後半のUnix V7の元の実装を見てみると、sed数値アドレスの動作が意図されていないか、少なくとも完全に考慮されていないようです。

代わりに、Geoffが仕様を読んだ後(そしてそれが起こった理由の元の説明)、次の場所にあります。

seq 5 | sed -n '3d;1,3p'

ライン1、2、4、5は、今回は1,3prangedコマンドが一度も会ったことのないエンドアドレスであるため、出力する必要があります。seq 5 | sed -n '3d;/1/,/3/p'

しかし、これは元の実装では発生せず、私が試した他の実装では発生しません(busyboxはバグのようsedに見える行1、2、および4を返します)。

見たらUNIX v7コード、現在の行番号が次であることを確認します。大きい(番号) 終了アドレスより範囲外です。実は開始アドレスについてはこれを行いません。意図したデザインというよりは間違いに見えます。

これは、現在の実装が実際にこの側面のPOSIX仕様の解釈に従わないことを意味します。

GNU実装の別の混乱した動作は次のとおりです。

$ seq 5 | sed -n '2d;2,/3/p'
3
4
5

2行目はスキップしたので、3行目2,/3/に入力してください(数字が2より大きい最初の行)。しかし、私たちを作るのはこのラインです。入力する範囲、未確認終わり住所状況がさらに悪化しますbusybox sed

$ seq 10 | busybox sed -n '2,7d; 2,3p'
8

2〜7行が削除されたため、8行は最初の行> = 2なので、2,3の範囲は次のようになります。入力するそれから!

おすすめ記事