次の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)
で保存したいと思います。このプロセスが「ライブ」で実行される場合、変更は基本的にチュートリアル全体を再入力すること(悪い)、または出力を「把握する」ことを意味し、長い編集セッションに基づく可能性があります(悪い)。
まあ、それをいじくり回した後、これは私が使用するものです:
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
これにより、xaa
、xab
...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*
.。
ユーザーがコマンドを入力し、応答を待機する(または、ターゲットが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
行、またはこの特定のケースでは、ed
(P
コマンド)のプロンプト文字を有効にして、*
は各ed
コマンドの前に表示されます。
私は何かをしました...複雑です。私は最近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つの長い正規表現は、スクリプト全体の実質的にすべてのテストを処理します。
アイデアは、私が知る限り、a
ppend、i
nsert、またはc
hangeコマンド。 挿入モードでは、文字通り、.
ドットのみで構成される次の行まですべての入力を受け取ります。複数行にまたがるその他の継続コマンド(G
、g
、V
、またはv
が含まれる一連のコマンド)は、必然的に末尾に\
backslashが付いた次の行-ただし、通常どおり、\
backslashはそのコンテキストでエスケープされます。
ですから、私が間違っている可能性は完全にありますが、私はthinkこれはすべてのケースを処理します。 [aic]
... .
dot series sed
に一致しないすべての入力行に対して、次のような一連のコマンドを挿入します。
0i
command-line$
.
1,.p
u
... ed
にi
nsertに明確なl
ook (sed
によって記述された)を独自のコマンドで指示し、次にp
rint it、そして最後にu
ndo全体の操作を行います-これは、編集を完了し、印刷し、元に戻すという非常に便利な結果をもたらしますそして最後を復元します単一のアクションでアドレス。
doが末尾の円記号または[aic]
... .
シリーズのいずれかのシーケンスで一致する行の場合、もう少し複雑になります。そのような場合、sed
は、l
ookを実行する前に、シリーズの最後に到達するまで再帰的にそれらをプルします。 [aic]
、.
、および実際のリテラル入力を別々のプリントに分割するように注意しました。これらのタイプはそれぞれ独自のl
ookを取得します。そのため、リテラル入力は次のようにまとめられます。可能な限り(sed
はデフォルトでl
ook出力を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$