ed(1)でこの正規表現範囲を印刷できないのはなぜですか?

ed(1)でこの正規表現範囲を印刷できないのはなぜですか?

edを使用してこの範囲を印刷できない理由は完全に混乱しています。範囲が2つの場合-望むよりファイル2.tfファイル-;が印刷できる場合は次のとおりです。範囲-望むよりファイル1.tfファイル - gsed(macOSではGNU sed)コマンドを使用して印刷できますが、edでは印刷できません。私のシェルセッションを考慮して、私の誤解を明確にしてください。

$ ed -s file1.tf <<<',n'
1   # some comment
2   module "hello_world" {
3     source = "./mydir"
4   }
5   # another comment
$ ed -s file1.tf <<<'/module.*world/,/}/p'
module "hello_world" {
  source = "./mydir"
}
$ ed -s file2.tf <<<',n'
1   # some comment
2   module "hello_world" {
3     source = "./mydir"
4   }
5   # another comment
6   # some comment
7   module "hello_again" {
8     source = "./anotherdir"
9   }
10  # another comment
$ ed -s file2.tf <<<'/module.*again/,/}/p'
?
$ gsed -n '/module.*again/,/}/p' file2.tf
module "hello_again" {
  source = "./anotherdir"
}

更新:反対方向は機能しますが、理由はわかりません。

$ ed -s file2.tf <<<'?module.*again?,?}?p'
module "hello_again" {
  source = "./anotherdir"
}

更新2:この??方法は実際に期待どおりに機能しません。三部ファイル3.tfファイル例)説明については回答を参照してください。

$ ed -s file3.tf <<<,n
1   # some comment
2   module "hello_world" {
3     source = "./mydir"
4   }
5   # another comment
6   # some comment
7   module "hello_again" {
8     source = "./anotherdir"
9   }
10  # another comment
11  # some comment
12  module "hello_yet_again" {
13    source = "./yetanotherdir"
14  }
15  # another comment
$ ed -s file3.tf <<<'?module.*hello_again?,?}?p'
module "hello_again" {
  source = "./anotherdir"
}
# another comment
# some comment
module "hello_yet_again" {
  source = "./yetanotherdir"
}

ベストアンサー1

問題の原因との違いは、ed正規表現のアドレス範囲がどのように処理されるかです。sed

では、sed最初に最初の行を見つけてから、最後の行が見つかるまですべての行にコマンドを適用します。

ed一方、 では、範囲の開始線と終了線は現在の行に基づいて計算されます。これにより、そのライン範囲内のすべてのラインにコマンドが適用されます。

/module.*again/, /}/in と 2 番目の file を使用する場合、ed現在の行はファイルの末尾にあります (ただし、バッファにロードしたからです)。範囲の開始行は行7と評価され、終了行は行4(2番目の式と一致する現在の行の後の最初の行)です。後方に実行される範囲を持つことができないため、エラーが発生します。

を使用すると、?module.*again?, ?}?検索は逆に機能するため、範囲の先頭は前のように7行として計算されますが(1行だけ式に一致するmodule.*again)、範囲の終わりは7より大きい9行なので同じ質問ではありません。

あなたの解決策はいいえ?正規表現区切り文字の代わりに in を使用して検索を逆にすると、3 つの部分/のうち中間を正しく見つけることができません (例には 2 つの部分しかありません)。代わりに、まずカーソルを範囲の最初の行に移動してから、その行からセクションの終わりまでコマンドを適用します。

/module.*again/; /}/ p

これは非常によく似ていますが、代わりに/module.*again/, /}/ p使用すると、開始アドレスが見つかるまで終了アドレスは計算されません。これは他の選択肢がないため(文書全体をメモリに保存しない)、範囲を処理する基本的な方法です。;,sed

この式は、基本的にカーソルを範囲の先頭に明示的に移動し、現在の行からセクションの終わりまでコマンドを適用するより長い式と同じです。

/module.*again/; ., /}/ p

POSIX仕様ed,vsについて話す内容は次のとおりです;

<comma>,アドレスは()または<semicolon>文字()で区切る必要があります;。区切り文字がある場合、<semicolon>現在の行(.)は2番目のアドレスが計算される前に最初のアドレスに設定されます。この機能は、順方向検索と逆方向検索の開始線を決定するために使用できます。

おすすめ記事