两个子进程可以同时向 Tcl/Expect 脚本内的 stdout 发送消息吗?

问题描述 投票:0回答:1

我编写了一个 Expect 脚本,它生成一个子进程 (certbot),解析输出,然后使用从第一个子进程提取的数据执行第二个子进程(Python 脚本),最后向第一个子进程发送回车符 (

\r
) 。我最近正在调试我的脚本的一个问题,所以我想我应该向 Python 脚本添加一些日志记录(以前不打印任何输出)。但是,这样做会导致期望脚本返回此错误:

    while executing
"exec ./test2.py "$SITE_DOMAIN" "$fileName" "$fileData""
    (file "./test.exp" line 23)

然后我尝试将对第二个进程/Python 脚本的调用从

exec
调用更改为
spawn
调用。这部分有效并且消除了错误。但奇怪的是,我一直看到第一个进程的输出,直到我开始看到第二个进程的输出。一旦第二个进程开始记录消息,我就不再看到第一个进程的任何输出。

我在此处包含文件来说明作为 MRE 的问题:

main.exp

#!/usr/bin/expect
set SITE_DOMAIN $env(SITE_DOMAIN)
set SITE_EMAIL $env(SITE_EMAIL)

# Spawn the certbot process
spawn ./test1.py certonly -m "$SITE_EMAIL" --agree-tos --no-eff-email --force-renew --preferred-challenges http --manual -d "$SITE_DOMAIN" -d "www.$SITE_DOMAIN"
set certbot_spawn_id $spawn_id

# Expect the output starting with 40 hyphens and capture it
expect {
    -re {(?n)^(- ){39}-\r\nCreate a file containing just this data:\r\n\r\n([\w.-]+)\r\n\r\nAnd make it available on your web server at this URL:\r\n\r\n.+/acme-challenge/([\w.-]+)} {
        set fileData $expect_out(2,string)
        set fileName $expect_out(3,string)
    }
    timeout {
        "Error: output from certbot did not match the expected pattern"
        exit 1
    }
}

# Call a separate command with the parsed value
exec ./test2.py "$SITE_DOMAIN" "$fileName" "$fileData"

# Send Enter to the certbot process to confirm
send -i $certbot_spawn_id "\r"

# Wait for the certbot process to finish
expect eof

test1.py

#!/usr/bin/env python
OUTPUT = """
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Requesting a certificate for example.com and www.example.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq.rstuvwxyz01234567890ABCDEFGHIJKLMNOPQRSTUVW

And make it available on your web server at this URL:

http://example.com/.well-known/acme-challenge/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopq

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"""

print(OUTPUT)
thing = input()
print("done")

test2.py

#!/usr/bin/env python
import logging
from time import sleep

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logging.basicConfig()

logger.info("Uploading file to web server")
sleep(2)
logger.info("Upload complete")
sleep(1)

因此,如果您按原样运行 main.exp,您将看到我提到的第一个错误。 (如果您从 test2.py 中删除日志语句,这些错误就会消失。)如果您将 main.exp 的第 22 行更改为使用

spawn
而不是
exec
,那也将修复错误,但是那么你就不会看到第一个进程输出的单词
done
。最后显示的内容将是
Upload complete

logging stdout expect
1个回答
0
投票
  1. Python 的
    logging
    将日志消息打印到 stderr
  2. Tcl 的
    exec
    如果看到任何输出到 stderr,则会引发错误。

示例:

$ expect -c 'exec bash -c "echo hello >&2" '
hello
    while executing
"exec bash -c "echo hello >&2" "

Tcl 的

exec
有选项
-ignorestderr
可以阻止它在这种情况下引发错误:

$ expect -c 'exec -ignorestderr bash -c "echo hello >&2" '
hello

来自 Tcl 的

exec
文档:

如果标准输出尚未重定向,则

exec
命令返回最后一个的标准输出 管道中的命令,除非指定了
2>@1
,在这种情况下也包括标准错误。 如果 管道中的任何命令异常退出或被终止或暂停,则
exec
将返回错误 错误消息将包括管道的输出,后跟描述异常的错误消息 终止;
-errorcode
返回选项将包含有关最后一个异常的附加信息 遇到终止。 如果任何命令写入其标准错误文件,并且该标准错误不是 重定向且未指定
-ignorestderr
,则
exec
将返回错误;错误消息将包括
管道的标准输出,然后是有关异常终止的消息(如果有),然后是
标准错误输出。

© www.soinside.com 2019 - 2024. All rights reserved.