Ecoando stdin ao executar um script ed (1)

5

Dado o seguinte script ed ,

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

Eu gostaria de obter de alguma forma a saída interativa

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

em vez do esperado

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

Isso é possível, talvez usando um utilitário de terceiros? Obrigado antecipadamente!

Edit: Acho que devo adicionar alguma motivação. Eu gostaria de produzir algumas sessões de exemplo, e provavelmente salvá-las com script(1) . Se este processo for executado "ao vivo", qualquer modificação implicaria basicamente digitar todo o tutorial novamente (ruim) ou alternativamente "descobrir" a saída, potencialmente baseada em uma longa sessão de edição (pior).

    
por ezequiel-garzon 29.12.2014 / 21:47

3 respostas

3

Bem, depois de brincar com isso, é isso que eu usaria:

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

ou, sem tee :

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

Se print >"/dev/stderr" não funcionar no seu sistema, você poderá usar print | "cat >&2" .

com gnu sed :

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

Outra maneira que funciona bem:
Use split para dividir seu edscript em cada linha:

split -l1 edscript

isso produzirá peças como xaa , xab ... xah .
Você poderia então usar as peças assim:

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

ou

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

para obter o resultado esperado. Então você rm x* ...

    
por 18.03.2015 / 03:22
3

Parece que você deseja simular uma sessão de terminal interativa, na qual o usuário digita um comando, aguarda uma resposta (ou, dado que o destino é ed , às vezes aguarda por um resposta), em seguida, digita outro comando, etc. Você pode escrever um script expect para fazer isso, mas pode ser bom o suficiente para enviar uma linha de cada vez para o terminal eo processo de destino, com uma breve pausa entre cada linha.

    $ 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

Para distinguir melhor a entrada da saída, você pode adicionar cor ou outro realce à linha echo "$line" >/dev/tty , ou, nesse caso específico, habilitar o caractere de prompt em ed (o comando P ) para que * será exibido na frente de cada comando ed .

    
por 29.12.2014 / 23:29
2

Eu fiz algo ... complicado. Eu tenho procurado ex / ed recentemente - eu não sou muito bom com ambos - e isso marcou uma oportunidade para mergulhar um pouco mais. Isso analisa o script ed primeiro e passa para ed in-stream:

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///;:n" -e 'G;//{N;D
    };g;s///;l;x;s///;l;H;s/.*/./;a\' -e '.
};l;g;i\' -e .\ -e 1,.p\ -e u <ed_script | ed

É menos complicado do que antes - e agora praticamente toda a complicação está em um único regex que abrange duas linhas. Aquele regex longo manipula virtualmente todos os testes para todo o script.

A ideia é que, por mais que eu saiba, você só pode acessar o modo inserir com um dos comandos a ppend, i nsert ou c hange . O modo insert toma todas as entradas literalmente até a próxima linha que ocorre, consistindo apenas em . dot. Qualquer outro comando continuado que abranja várias linhas - até mesmo uma sequência desse tipo em que G , g , V ou v estão envolvidos - é necessariamente continuado para a próxima linha com uma barra invertida \ - embora , como de costume, um \ barra invertida se escapa nesse contexto.

Então, embora seja totalmente possível, estou enganado, acho que lida com todos os casos. Para cada linha de entrada que não corresponde a [aic] ... . ponto series sed insere uma série de comandos que se parece com:

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

... instruindo ed a i a inserir um inequívoco l ook (conforme escrito por sed ) em seu próprio comando, em seguida, p rint it e durar para u ndo toda a operação - que tem o resultado muito conveniente de fazer a edição, imprimi-la, invertê-la, e restaurando o último endereço em uma única ação.

Para aqueles que as linhas que fazem correspondem em uma sequência de barras invertidas ou de uma série [aic] ... . , é um pouco mais complicado. Nesses casos, sed recursivamente os puxa até encontrar o final da série antes de fazer seu l ook. Tive o cuidado de separar o [aic] , . e a entrada literal real em impressões separadas - cada um desses tipos obterá seu próprio l ook - de modo que a entrada literal seja amarrada o máximo possível ( sed irá quebrar uma saída l ook em 80 caracteres por padrão) .

Acho mais fácil mostrar a você. Você notará o prompt ? abaixo - isso ocorre porque o comando g fornecido antes dele não é válido - não porque sed manipula a entrada (espero) . Aqui está a saída de uma versão modificada do seu conjunto de dados de exemplo:

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$
    
por 31.12.2014 / 19:48

Tags