-
Notifications
You must be signed in to change notification settings - Fork 0
fix(bash): sed replacement escaping, BSD portability, dead cleanup code #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
8f97d7e
1661ddb
3280cd7
e4933f9
e26a1e6
414d016
aac7864
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -117,13 +117,17 @@ log_warning() { | |||||||||||||||||||||||||||||||
| echo "WARNING: $1" >&2 | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # Track temporary files for cleanup on interrupt | ||||||||||||||||||||||||||||||||
| _CLEANUP_FILES=() | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # Cleanup function for temporary files | ||||||||||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||||||||||
| local exit_code=$? | ||||||||||||||||||||||||||||||||
| # Disarm traps to prevent re-entrant loop | ||||||||||||||||||||||||||||||||
| trap - EXIT INT TERM | ||||||||||||||||||||||||||||||||
| rm -f /tmp/agent_update_*_$$ | ||||||||||||||||||||||||||||||||
| rm -f /tmp/manual_additions_$$ | ||||||||||||||||||||||||||||||||
| for f in "${_CLEANUP_FILES[@]+"${_CLEANUP_FILES[@]}"}"; do | ||||||||||||||||||||||||||||||||
| rm -f "$f" "$f.bak" "$f.tmp" | ||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||
| exit $exit_code | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
@@ -284,7 +288,8 @@ get_language_conventions() { | |||||||||||||||||||||||||||||||
| create_new_agent_file() { | ||||||||||||||||||||||||||||||||
| local target_file="$1" | ||||||||||||||||||||||||||||||||
| local temp_file="$2" | ||||||||||||||||||||||||||||||||
| local project_name="$3" | ||||||||||||||||||||||||||||||||
| local project_name | ||||||||||||||||||||||||||||||||
| project_name=$(printf '%s\n' "$3" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
| local current_date="$4" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if [[ ! -f "$TEMPLATE_FILE" ]]; then | ||||||||||||||||||||||||||||||||
|
|
@@ -307,18 +312,21 @@ create_new_agent_file() { | |||||||||||||||||||||||||||||||
| # Replace template placeholders | ||||||||||||||||||||||||||||||||
| local project_structure | ||||||||||||||||||||||||||||||||
| project_structure=$(get_project_structure "$NEW_PROJECT_TYPE") | ||||||||||||||||||||||||||||||||
| project_structure=$(printf '%s\n' "$project_structure" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| local commands | ||||||||||||||||||||||||||||||||
| commands=$(get_commands_for_language "$NEW_LANG") | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| local language_conventions | ||||||||||||||||||||||||||||||||
| language_conventions=$(get_language_conventions "$NEW_LANG") | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # Perform substitutions with error checking using safer approach | ||||||||||||||||||||||||||||||||
| # Escape special characters for sed by using a different delimiter or escaping | ||||||||||||||||||||||||||||||||
| local escaped_lang=$(printf '%s\n' "$NEW_LANG" | sed 's/[\[\.*^$()+{}|]/\\&/g') | ||||||||||||||||||||||||||||||||
| local escaped_framework=$(printf '%s\n' "$NEW_FRAMEWORK" | sed 's/[\[\.*^$()+{}|]/\\&/g') | ||||||||||||||||||||||||||||||||
| local escaped_branch=$(printf '%s\n' "$CURRENT_BRANCH" | sed 's/[\[\.*^$()+{}|]/\\&/g') | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| # Escape special characters for sed replacement strings (right side of s|pattern|replacement|) | ||||||||||||||||||||||||||||||||
| # & and \ are replacement-side specials; | must also be escaped because it's our sed delimiter | ||||||||||||||||||||||||||||||||
| local escaped_lang=$(printf '%s\n' "$NEW_LANG" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
| local escaped_framework=$(printf '%s\n' "$NEW_FRAMEWORK" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
| commands=$(printf '%s\n' "$commands" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
| language_conventions=$(printf '%s\n' "$language_conventions" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
| local escaped_branch=$(printf '%s\n' "$CURRENT_BRANCH" | sed 's/[\\&|]/\\&/g') | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
| local escaped_lang=$(printf '%s\n' "$NEW_LANG" | sed 's/[\\&|]/\\&/g') | |
| local escaped_framework=$(printf '%s\n' "$NEW_FRAMEWORK" | sed 's/[\\&|]/\\&/g') | |
| commands=$(printf '%s\n' "$commands" | sed 's/[\\&|]/\\&/g') | |
| language_conventions=$(printf '%s\n' "$language_conventions" | sed 's/[\\&|]/\\&/g') | |
| local escaped_branch=$(printf '%s\n' "$CURRENT_BRANCH" | sed 's/[\\&|]/\\&/g') | |
| # Helper function to escape special characters for sed replacement strings | |
| escape_sed() { | |
| printf '%s\n' "$1" | sed 's/[\\&|]/\\&/g' | |
| } | |
| local escaped_lang=$(escape_sed "$NEW_LANG") | |
| local escaped_framework=$(escape_sed "$NEW_FRAMEWORK") | |
| commands=$(escape_sed "$commands") | |
| language_conventions=$(escape_sed "$language_conventions") | |
| local escaped_branch=$(escape_sed "$CURRENT_BRANCH") |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Bash, when set -e is active, a failure in a command that is part of a && or || list (except for the last command in the list) will not trigger an immediate exit. Here, if awk fails, the mv command is skipped, but the script will continue executing, leading to a silent failure where the template placeholders are not correctly expanded. It is safer to separate these into two distinct commands so that set -e can catch a failure in either.
| awk '{gsub(/\\n/,"\n")}1' "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" | |
| awk '{gsub(/\\n/,"\\n")}1' "$temp_file" > "$temp_file.tmp" | |
| mv "$temp_file.tmp" "$temp_file" |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The split of AGENTS_FILE updates into individual calls for Amp, Kiro CLI, IBM Bob, and Forge is redundant and causes a regression in logging. Because _update_if_new uses realpath to deduplicate updates, only the first call (Codex/opencode) will actually execute. Subsequent calls for the same file will be skipped, meaning the specific agent names like "Forge" will never be logged during a full update. Additionally, "Pi" has been removed from the list entirely. It is better to use a combined name for shared files to ensure all relevant agents are represented in the logs and no agents are missed.
| _update_if_new "$CURSOR_FILE" "Cursor IDE" || _all_ok=false | |
| _update_if_new "$QWEN_FILE" "Qwen Code" || _all_ok=false | |
| _update_if_new "$AGENTS_FILE" "Codex/opencode/Amp/Kiro/Bob/Pi/Forge" || _all_ok=false | |
| _update_if_new "$AGENTS_FILE" "Codex/opencode" || _all_ok=false | |
| _update_if_new "$AMP_FILE" "Amp" || _all_ok=false | |
| _update_if_new "$KIRO_FILE" "Kiro CLI" || _all_ok=false | |
| _update_if_new "$AGENTS_FILE" "Codex/opencode/Amp/Kiro/Bob/Pi/Forge" || _all_ok=false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The array expansion
"${_CLEANUP_FILES[@]+"${_CLEANUP_FILES[@]}"}"inside double quotes will expand to an empty string""if the array is empty in older Bash versions (like 3.2 on macOS). This causes the loop to run once withfas an empty string, leading torm -f "" ".bak" ".tmp". This is dangerous as it will attempt to delete files named.bakand.tmpin the current working directory if they exist. To fix this, remove the outer double quotes so it expands to nothing when the array is empty.