Como eu espero uma nova linha no script esperado?

3

Considere este script interativo:

#!/usr/bin/env bash
set -eu
while true; do
    read -p '> '
    if [ "$REPLY" == quit ]; then
        break
    fi
    echo "'$REPLY'"
done

Agora quero que expect interaja com ele:

#!/usr/bin/env bash
set -eu
echo '
    spawn ./1.sh
    expect >
    send cmd1\n
    expect {\n> }
    send quit\n
' | expect -d

Mas quando eu o executo, diz:

...
expect: does " cmd1\r\n'cmd1'\r\n> " (spawn_id exp6) match glob pattern "\n> "? no
expect: timed out
send: sending "quit\n" to { exp6 }

Por que não combina? Como posso detectar a aparição de um novo prompt (terminando um comando)?

    
por x-yuri 03.09.2017 / 01:14

2 respostas

2

tl; dr Adicione -ex flag.

A questão aqui é que expect torna mais fácil passar argumentos complexos para alguns comandos ( expect / interact ):

The commands that accepted arguments braced into a single list (the expect variants and interact) use a heuristic to decide if the list is actually one argument or many. The heuristic can fail only in the case when the list actually does represent a single argument which has multiple embedded \n's with non-whitespace characters between them. This seems sufficiently improbable, however the argument "-nobrace" can be used to force a single argument to be handled as a single argument. This could conceivably be used with machine-generated Expect code. Similarly, -brace forces a single argument to be handle as multiple patterns/actions.

(from description of expect command) If the arguments to the entire expect statement require more than one line, all the arguments may be "braced" into one so as to avoid terminating each line with a backslash. In this one case, the usual Tcl substitutions will occur despite the braces.

Deixe-me dar um exemplo aqui:

#!/usr/bin/env bash
set -eu
f() {
    echo line 1
    sleep 1
    echo line 2
}
export -f f
echo '
    spawn bash -c f
    expect {
        {line 1} {puts 1}
        {line 2} {puts 2}
    }
    expect \
        {line 1} {puts 1} \
        {line 2} {puts 2}
' | expect

Saída:

spawn bash -c f
line 1
1
line 2
2

No repositório que encontrei, o heurística no commit mais recente (maio de 2014) é da seguinte forma : se um argumento for passado e houver uma nova linha antes do primeiro não-espaço em branco, o argumento será considerado como múltiplos argumentos em um.

    
por 18.10.2017 / 18:31
2

No idioma expect tcl , há uma diferença entre as strings citadas com "" e {} . Você pode ver isso nos 2 exemplos:

$ expect -c 'puts "a\nb"'
a
b
~ $ expect -c 'puts {a\nb}'
a\nb

Seu padrão de glob {\n> } consiste em 4 caracteres para corresponder, mas o \n não é especialmente interpretado como um escape. Se você usar o padrão "\n> " , sua correspondência deverá funcionar. Ou você pode usar o sinalizador -re em vez do padrão glob padrão, e os dois caracteres serão interpretados pelo código regexp como um escape, -re {\n> } .

    
por 03.09.2017 / 14:39