diff --git a/konabot/plugins/handle_text/base.py b/konabot/plugins/handle_text/base.py index b199ae3..b9d23c3 100644 --- a/konabot/plugins/handle_text/base.py +++ b/konabot/plugins/handle_text/base.py @@ -161,9 +161,9 @@ class PipelineRunner: "'": "'", } - def flush_word(): + def flush_word(force: bool = False): nonlocal buf - if buf: + if buf or force: tokens.append(Token(TokenKind.WORD, buf)) buf = "" @@ -178,6 +178,7 @@ class PipelineRunner: escape = True elif c == quote: quote = None + flush_word(force=True) # 引号闭合时强制 flush,即使是空字符串 else: buf += c i += 1 @@ -188,7 +189,7 @@ class PipelineRunner: i += 1 continue - if c.isspace() or c in "  ": + if c.isspace(): flush_word() i += 1 continue diff --git a/konabot/plugins/handle_text/handlers/unix_handlers.py b/konabot/plugins/handle_text/handlers/unix_handlers.py index 16e210d..1434e15 100644 --- a/konabot/plugins/handle_text/handlers/unix_handlers.py +++ b/konabot/plugins/handle_text/handlers/unix_handlers.py @@ -13,10 +13,8 @@ class THEcho(TextHandler): async def handle( self, env: TextHandlerEnvironment, istream: str | None, args: list[str] ) -> TextHandleResult: - if len(args) == 0 and istream is None: - return TextHandleResult(1, "请在 echo 后面添加需要输出的文本") - if istream is not None: - return TextHandleResult(0, "\n".join([istream] + args)) + # echo 不读 stdin,只输出参数(Unix 语义) + # 无参数时输出空行(与 Unix echo 行为一致) return TextHandleResult(0, "\n".join(args)) diff --git a/tests/test_textfx_shell.py b/tests/test_textfx_shell.py index 5e7def7..10f0636 100644 --- a/tests/test_textfx_shell.py +++ b/tests/test_textfx_shell.py @@ -205,3 +205,21 @@ async def test_while_body_can_use_if(runner: PipelineRunner): assert not isinstance(parsed, str) results = await runner.run_pipeline(parsed, None, TextHandlerEnvironment(False)) assert results[0].code == 1 + + +@pytest.mark.asyncio +async def test_echo_empty_string(runner: PipelineRunner): + """测试 echo 空字符串""" + # 双引号空字符串 + parsed = runner.parse_pipeline('echo ""') + assert not isinstance(parsed, str) + results = await runner.run_pipeline(parsed, None, TextHandlerEnvironment(False)) + assert results[0].code == 0 + assert results[0].ostream == '' + + # 单引号空字符串 + parsed2 = runner.parse_pipeline("echo ''") + assert not isinstance(parsed2, str) + results2 = await runner.run_pipeline(parsed2, None, TextHandlerEnvironment(False)) + assert results2[0].code == 0 + assert results2[0].ostream == ''