运行 ed(1) 脚本时回显 stdin

运行 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
$

这可能吗,也许使用第三方实用程序?提前致谢!

编辑:我想我应该增加一些动力。我想制作一些示例编辑会话,并可能将它们保存为script(1).如果这个过程是“实时”执行的,任何修改基本上都意味着再次输入整个教程(不好),或者“弄清楚”输出,可能基于长时间的编辑会话(更糟糕)。

答案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来分割你的编辑脚本每行:

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*...

答案2

听起来您想模拟一个交互式终端会话,其中用户键入命令,等待响应(或者,假设目标是ed有时等待响应),然后键入另一个命令等。您可以编写一个expect脚本来执行此操作,但一次只向终端和目标进程发送一行可能就足够了,中间有短暂的停顿每行。

    $ 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中的提示字符,以便 a将显示在每个命令的前面。edP*ed

答案3

我做了一些……复杂的事情。我最近一直在研究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

它没有以前那么复杂 - 现在几乎所有的复杂性都集中在跨越两行的单个正则表达式中。这一长长的正则表达式几乎处理整个脚本的所有测试。

据我所知,这个想法是,你只能到达插入a模式与pend、insert 或之一change 命令插入然后,模式将所有输入字面地接受到下一个仅由.点组成的行。任何其他跨越多行的连续命令 - 即使涉及GgV或的序列v- 都必须继续到带有尾随\反斜杠的下一行 - 尽管像往常一样,\反斜杠在该上下文中会自行转义。

所以,虽然我完全有可能错了,但我思考这可以处理所有情况。对于与[aic]... .点系列不匹配的每个输入行,sed插入一系列如下所示的命令:

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

...指示ed插入i明确的look(如所写sed按照它自己的命令,然后p打印它,最后到u完成整个操作 - 这具有完成编辑、打印它、反转它的非常方便的结果,通过单个操作恢复最后一个地址。

对于那些符合以下条件的人匹配尾随反斜杠的序列或[aic]....系列,这有点复杂。在这些情况下,sed会递归地将它们拉入,直到遇到该系列的末尾,然后再执行l操作。我小心地将[aic].和 实际文字输入分成单独的打印 - 每个类型都会有自己的look - 以便文字输入尽可能地串在一起(默认情况下sed将在 80 个字符处中断look 输出)

我想向您展示会更容易。您会注意到?下面的提示 - 发生这种情况是因为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$

相关内容