( command: string, addStdinRedirect: boolean = true, )
| 44 | * @returns The properly quoted command |
| 45 | */ |
| 46 | export function quoteShellCommand( |
| 47 | command: string, |
| 48 | addStdinRedirect: boolean = true, |
| 49 | ): string { |
| 50 | // If command contains heredoc or multiline strings, handle specially |
| 51 | // The shell-quote library incorrectly escapes ! to \! in these cases |
| 52 | if (containsHeredoc(command) || containsMultilineString(command)) { |
| 53 | // For heredocs and multiline strings, we need to quote for eval |
| 54 | // but avoid shell-quote's aggressive escaping |
| 55 | // We'll use single quotes and escape only single quotes in the command |
| 56 | const escaped = command.replace(/'/g, "'\"'\"'") |
| 57 | const quoted = `'${escaped}'` |
| 58 | |
| 59 | // Don't add stdin redirect for heredocs as they provide their own input |
| 60 | if (containsHeredoc(command)) { |
| 61 | return quoted |
| 62 | } |
| 63 | |
| 64 | // For multiline strings without heredocs, add stdin redirect if needed |
| 65 | return addStdinRedirect ? `${quoted} < /dev/null` : quoted |
| 66 | } |
| 67 | |
| 68 | // For regular commands, use shell-quote |
| 69 | if (addStdinRedirect) { |
| 70 | return quote([command, '<', '/dev/null']) |
| 71 | } |
| 72 | |
| 73 | return quote([command]) |
| 74 | } |
| 75 | |
| 76 | /** |
| 77 | * Detects if a command already has a stdin redirect |
no test coverage detected