Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 29, 2026

Fix multi-line init commands being split by startup script

Problem

The startup script at /ssh/rootfs/etc/s6-overlay/s6-rc.d/init-user/run was using while read -r cmd to process init_commands, which splits on newlines. This caused multi-line commands (like heredocs) to be incorrectly split into multiple separate commands, resulting in syntax errors.

Solution Implemented

  • Analyze the issue and understand the root cause
  • Fix the init_commands processing to handle multi-line commands properly using array index iteration
  • Test the fix manually with multi-line heredoc commands
  • Add error handling for array operations
  • Use bashio::config abstraction instead of direct file access
  • Run shellcheck linter
  • Address code review feedback

Changes Made

Modified /ssh/rootfs/etc/s6-overlay/s6-rc.d/init-user/run (lines 109-122):

Before:

if bashio::config.has_value 'init_commands'; then
    while read -r cmd; do
        eval "${cmd}" \
            || bashio::exit.nok "Failed executing init command: ${cmd}"
    done <<< "$(bashio::config 'init_commands')"
fi

After:

if bashio::config.has_value 'init_commands'; then
    # Use bashio::config to properly iterate over the array, preserving multi-line commands
    length=$(bashio::config 'init_commands | length') \
        || bashio::exit.nok 'Failed to get init_commands array length'
    
    for (( i=0; i<length; i++ )); do
        cmd=$(bashio::config "init_commands[${i}]") \
            || bashio::exit.nok "Failed to get init command at index ${i}"
        
        eval "${cmd}" \
            || bashio::exit.nok "Failed executing init command: ${cmd}"
    done
fi

Key Improvements

  1. Preserves multi-line strings: Using array index iteration ensures each command is extracted as a complete string, including embedded newlines
  2. Uses bashio abstraction: Now uses bashio::config with jq-style queries instead of directly accessing /data/options.json
  3. Proper error handling: Added error checking for array operations
  4. Maintains compatibility: Single-line commands continue to work exactly as before

Testing Completed

✅ Simple single-line commands
✅ Multi-line heredoc commands
✅ Complex commands with special characters
✅ bashio::config abstraction layer
✅ Shellcheck linter passed

Original prompt

This section details on the original issue you should resolve

<issue_title>Multi-line init commands are implicitly split by startup script</issue_title>
<issue_description>I have this in my configuration.yaml for this great add-on:

init_commands:
  - cp -ar /data/system/* /
  - pip install --break-system-packages mpremote
  - |
    cat >> ~/.zshrc <<'EOF'
    # Use GNU nano as default editor in shell
    export EDITOR=nano

    # Enable command-not-found integration
    command_not_found_handler() {
        /usr/libexec/command-not-found "$@";
    }
    EOF

As you can see it attempts to append several configuration lines to the Zshell configuration file on addon startup.

The newlines are correctly stored in the addon options (/mnt/data/supervisor/addons/data/a0d7b954_ssh/options.json):

{
  
  "init_commands": [
    "cp -ar /data/system/* /",
    "pip install --break-system-packages mpremote",
    "cat >> ~/.zshrc <<'EOF'\n# Use GNU nano as default editor in shell\nexport EDITOR=nano\n\n# Enable command-not-found integration\ncommand_not_found_handler() {\n    /usr/libexec/command-not-found \"$@\";\n}\nEOF\n"
  ]
}

However the add-on’s startup script breaks them into multiple lines:
https://github.com/hassio-addons/addon-ssh/blob/50c387cb56f30ea3acfd401a7978136ea392cc5a/ssh/rootfs/etc/s6-overlay/s6-rc.d/init-user/run#L110-L115

Causing errors when executing this code:

/etc/s6-overlay/s6-rc.d/init-user/run: line 112: warning: here-document at line 112 delimited by end-of-file (wanted `EOF')
/etc/s6-overlay/s6-rc.d/init-user/run: eval: line 113: syntax error: unexpected end of file
[21:04:49] FATAL: Failed executing init command: command_not_found_handler() {
s6-rc: warning: unable to start service init-user: command exited 1
/run/s6/basedir/scripts/rc.init: warning: s6-rc failed to properly bring all the services up! Check your logs (in /run/uncaught-logs/current if you have in-container logging) for more information.
/run/s6/basedir/scripts/rc.init: fatal: stopping the container.
```</issue_description>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: frenck <195327+frenck@users.noreply.github.com>
@frenck frenck added the bugfix Inconsistencies or issues which will cause a problem for users or implementors. label Jan 29, 2026
Co-authored-by: frenck <195327+frenck@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix multi-line init commands splitting issue Fix multi-line init commands being split on embedded newlines Jan 29, 2026
Copilot AI requested a review from frenck January 29, 2026 13:54
Co-authored-by: frenck <195327+frenck@users.noreply.github.com>
@frenck frenck marked this pull request as ready for review January 29, 2026 15:34
@coderabbitai
Copy link

coderabbitai bot commented Jan 29, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Comment @coderabbitai help to get the list of available commands and usage tips.

@frenck frenck merged commit 7291f39 into main Jan 29, 2026
13 checks passed
@frenck frenck deleted the copilot/fix-multi-line-init-commands branch January 29, 2026 15:35
@github-actions github-actions bot locked and limited conversation to collaborators Jan 31, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

bugfix Inconsistencies or issues which will cause a problem for users or implementors.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-line init commands are implicitly split by startup script

2 participants