Hooks: /bin/sh parses command before bash executes, breaking bash-specific syntax (<<<, process substitution, etc.)
Bug Description
When a hook's command field uses bash as the executable but includes bash-specific syntax like herestrings (<<<), the command fails with Syntax error: redirection unexpected because Claude Code uses /bin/sh to parse and execute the entire command string before bash gets invoked.
Reproduction
settings.json:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "bash ~/my-hook.sh tool_start <<< '{\"tool_name\":\"'\"$TOOL_NAME\"'\"}'",
"timeout": 5000
}
]
}
]
}
}
Expected: bash is invoked and handles the <<< herestring natively.
Actual: /bin/sh parses the command first, encounters <<<, and fails:
Syntax error: redirection unexpected
This happens on every tool call, making hooks unusable when bash-specific syntax is present.
Root Cause
Claude Code appears to execute hook commands via /bin/sh -c "<command>" (or equivalent). Since /bin/sh is POSIX sh on many systems (e.g., dash on Debian/Ubuntu), any bash-specific syntax in the command string is rejected at the shell parsing stage — before bash ever runs.
This affects at minimum:
- Herestrings:
<<< - Process substitution:
<(),>() - Arrays,
[[ ]], and other bashisms
Suggested Fix
A few options:
- Use
bash -cinstead ofsh -cto execute hook commands (may have portability concerns). - Document the limitation prominently — hook commands must use POSIX sh-compatible syntax only.
- Allow users to specify the shell for hook execution, e.g., a
"shell"field in the hook config.
Workaround
Rewrite commands to be POSIX-compatible. For example, replace:
"command": "bash ~/hook.sh tool_start <<< '{\"tool_name\":\"'\"$TOOL_NAME\"'\"}'"
With:
"command": "echo '{\"tool_name\":\"'\"$TOOL_NAME\"'\"}' | bash ~/hook.sh tool_start"
Or if the script doesn't actually read stdin (as was the case here), simply remove the herestring entirely.
Environment
- OS: Ubuntu (remote server),
/bin/sh→dash - Claude Code version: latest
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗