web-dev-qa-db-ja.com

ed(1)スクリプトの実行時にstdinをエコーする

次のedスクリプトが与えられた場合、

_$ cat helloworld
a
hello
world
.
,n
,s,o,O,g
,n
Q
_

どういうわけかインタラクティブな出力を取得したい

_$ ed
a
hello
world
.
,n
1   hello
2   world
,s,o,O,g
,n
1   hellO
2   wOrld
Q
$
_

期待される代わりに

_$ cat helloworld | ed
1   hello
2   world
1   hellO
2   wOrld
$
_

おそらくサードパーティのユーティリティを使用して、それは可能ですか?前もって感謝します!

編集:やる気を追加する必要があると思います。サンプルのedセッションをいくつか作成し、おそらくscript(1)で保存したいと思います。このプロセスが「ライブ」で実行される場合、変更は基本的にチュートリアル全体を再入力すること(悪い)、または出力を「把握する」ことを意味し、長い編集セッションに基づく可能性があります(悪い)。

6
ezequiel-garzon

まあ、それをいじくり回した後、これは私が使用するものです:

 awk '{ print; system("sleep 0") }' edscript | tee /dev/tty | ed

または、teeなし:

awk '{ print >"/dev/stderr"; print | "ed"; system("sleep 0") }' edscript

print >"/dev/stderr"がシステムで機能しない場合は、print | "cat >&2"を使用できます。


gnu sedの場合:

sed -u -n -e 'p;w /dev/stderr' -e 's|.*||e' edscript | ed

同様に機能する別の方法:
splitを使用して、各行でedscriptを分割します。

split -l1 edscript

これにより、xaaxab...xahのようなピースが生成されます。
次に、次のような部分を使用できます。

for i in x*; do awk '{ print >"/dev/stderr"; print }' $i; done | ed

または

for i in x*; do sed -n -e 'p;w /dev/stderr' $i; done | ed

期待される結果を得るために。次に、rm x*.。

4
don_crissti

ユーザーがコマンドを入力し、応答を待機する(または、ターゲットがedの場合、時々は応答)、次に別のコマンドなどを入力します。これを行うにはexpectスクリプトを作成できますが、ターミナルとターゲットプロセスの両方に一度に1行ずつ送信するだけで十分な場合があります。各行の間に短い一時停止。

    $ while IFS= read -r line
      do
        printf '%s\n' "$line" >/dev/tty
        printf '%s\n' "$line"
        sleep 0.5
      done < helloworld | ed
a
hello
world
.
,n
1   hello
2   world
,s,o,O,g
,n
1   hellO
2   wOrld
Q

入力と出力をより適切に区別するために、色やその他の強調表示をに追加できます。
echo "$line" >/dev/tty行、またはこの特定のケースでは、edPコマンド)のプロンプト文字を有効にして、*は各edコマンドの前に表示されます。

4
Mark Plotnick

私は何かをしました...複雑です。私は最近ex/edを調べていますが、どちらもあまり得意ではありません。これは、もう少し深く掘り下げる機会を示しました。これは、最初にedスクリプトを解析し、それをインストリームのedに渡します。

b='[:blank:]'
sed -e 'h;/\n/!i\' -e 0i -e 's/^\(.*[^\]\)*\(\\\\\)*\\$//;tn'"
/^\n*\([0-9;$,.$b]*[gGvV].*\\\\\n[$b]*\)*\([0-9,$.;${b}]*[aic][$b]*\)\
\(\n\(.*\)\n\.\)*\(\n.*\)*$/{ s//\4/;:n" -e 'G;//{N;D
    };g;s//\1\2/;l;x;s//\4/;l;H;s/.*/./;a\' -e '.
};l;g;i\' -e .\\ -e 1,.p\\ -e u <ed_script | ed

以前ほど複雑ではありませんでしたが、今では事実上すべての複雑さが2行にまたがる単一の正規表現にあります。その1つの長い正規表現は、スクリプト全体の実質的にすべてのテストを処理します。

アイデアは、私が知る限り、append、insert、またはchangeコマンド。 挿入モードでは、文字通り、.ドットのみで構成される次の行まですべての入力を受け取ります。複数行にまたがるその他の継続コマンド(GgV、またはvが含まれる一連のコマンド)は、必然的に末尾に\backslashが付いた次の行-ただし、通常どおり、\backslashはそのコンテキストでエスケープされます。

ですから、私が間違っている可能性は完全にありますが、私はthinkこれはすべてのケースを処理します。 [aic] ... . dot series sedに一致しないすべての入力行に対して、次のような一連のコマンドを挿入します。

0i
command-line$
.
1,.p
u

... edinsertに明確なlook sedによって記述された)を独自のコマンドで指示し、次にprint it、そして最後にundo全体の操作を行います-これは、編集を完了し、印刷し、元に戻すという非常に便利な結果をもたらしますそして最後を復元します単一のアクションでアドレス。

doが末尾の円記号または[aic] ... .シリーズのいずれかのシーケンスで一致する行の場合、もう少し複雑になります。そのような場合、sedは、lookを実行する前に、シリーズの最後に到達するまで再帰的にそれらをプルします。 [aic].、および実際のリテラル入力を別々のプリントに分割するように注意しました。これらのタイプはそれぞれ独自のlookを取得します。そのため、リテラル入力は次のようにまとめられます。可能な限りsedはデフォルトでlook出力を80文字で分割します)

見せるだけの方が簡単だと思います。以下の?プロンプトに気付くでしょう-これは、前に与えられたgコマンドが有効なコマンドではないために発生します-sedが入力をマングルするためではありません(私は願っています)。サンプルデータセットの変更バージョンからの出力は次のとおりです。

g \\\n  a$
hello\nworld\\\n\n  0a\n  world\\\nworld\nworld$
.$
?
,n$
1       hello
2       world\
3
4         0a
5         world\
6       world
7       world
,s,o,O,g$
4$
  0a
.,$n$
4         0a
5         wOrld\
6       wOrld
7       wOrld
,s,$,\\\n\\\n\\\\$
\
,n$
1       hellO
2
3       \
4       wOrld\
5
6       \
7
8
9       \
10        0a
11
12      \
13        wOrld\
14
15      \
16      wOrld
17
18      \
19      wOrld
20
21      \
Q$
3
mikeserv