diff --git a/src/lib/engine/shell/builtins.ts b/src/lib/engine/shell/builtins.ts index c0f9992..d49b611 100644 --- a/src/lib/engine/shell/builtins.ts +++ b/src/lib/engine/shell/builtins.ts @@ -160,21 +160,7 @@ async function echoCommand(args: string[], fs: FsLike, cwd: string): Promise file - const redirectMatch = content_raw.match(/^(.*?)\s*>\s*(.+)$/); - if (redirectMatch) { - let content = redirectMatch[1].replace(/^["']|["']$/g, ''); - if (escapeFlag) content = interpretEscapes(content); - const filepath = resolvePath(redirectMatch[2].trim(), cwd); - try { - await fs.promises.writeFile(filepath, content + '\n'); - return { output: '', success: true }; - } catch { - return { output: `echo: cannot write to '${redirectMatch[2]}'`, success: false }; - } - } - - // Handle append: echo [-e] "content" >> file + // Handle append: echo [-e] "content" >> file (must check before > to avoid >> being parsed as >) const appendMatch = content_raw.match(/^(.*?)\s*>>\s*(.+)$/); if (appendMatch) { let content = appendMatch[1].replace(/^["']|["']$/g, ''); @@ -189,6 +175,20 @@ async function echoCommand(args: string[], fs: FsLike, cwd: string): Promise file + const redirectMatch = content_raw.match(/^(.*?)\s*>(?!>)\s*(.+)$/); + if (redirectMatch) { + let content = redirectMatch[1].replace(/^["']|["']$/g, ''); + if (escapeFlag) content = interpretEscapes(content); + const filepath = resolvePath(redirectMatch[2].trim(), cwd); + try { + await fs.promises.writeFile(filepath, content + '\n'); + return { output: '', success: true }; + } catch { + return { output: `echo: cannot write to '${redirectMatch[2]}'`, success: false }; + } + } + let output = content_raw.replace(/^["']|["']$/g, ''); if (escapeFlag) output = interpretEscapes(output); return { output, success: true };