[GitHub Actions] - echo : bad substitution

청주는사과아님·2025년 6월 27일
1

Troubleshooting

목록 보기
6/7

최근 GitHub Actions 를 통해 CD 파이프라인을 실행 중, echo 커맨드로 인한 트러블 슈팅을 경험했습니다.

이번 포스팅은 이에 대한 원인과 그 해결법을 공유하고자 합니다.


📝 상황 설명

프로젝트에 구성한 CD 는 다음과 같은 모습을 하고 있습니다.

특히 이 중 build-and-push 는 어플리케이션을 build, 생성된 이미지를 Docker Hub 에 업로드하는 과정으로, 여러 "비밀 처리된" 프로필을 넣어주는 과정이 포함되어 있습니다.
(application-secret.yaml 등)

이에 사용하는 복합 액션은 다음처럼 구성되어 있습니다.

## 주어진 내용을 파일로 저장하는 composite action
name: Save to file

description: 'Save given context to file.'

inputs:
  context:
    required: true
    description: 'A context to be saved as a file'

  file_dir:
    required: true
    description: 'A directory where file will exist'

  file_name:
    required: true
    description: 'Name of the file to be saved'

runs:
  using: 'composite'

  steps:
    - name: Check whether duplicate exists
      shell: bash
      run: |
        if [ -f "${{ inputs.file_dir }}/${{ inputs.file_name }}" ]; then
          exit 1
        fi

    - name: Create directory if not exists
      shell: bash
      run: |
        mkdir -p "${{ inputs.file_dir }}"

    - name: Save context to destination
      shell: bash
      run: |
        echo "${{ inputs.context }}" > "${{ inputs.file_dir }}/${{ inputs.file_name }}"

하지만 이를 실행하니 아래와 같은 에러가 발생했습니다.

> Run echo ... 
***
  ***
  ***
  ***
  ***
  ***
  ***

***
: bad substitution
Error: Process completed with exit code 1.

📌 원인 분석

실패 원인은 저장하는 내용 중 ${...} 같은 형태가 존재하였기 때문입니다.
저희는 아래와 같은 yaml 프로필을 저장하고 있었습니다.

# application-prod-secret.yaml
# prod server has not been set yet

db:
  host:
  username:
  password:
  name:
  port:
  url: jdbc:mysql://${db.host}:${db.port}/${db.name}

spring.jpa.hibernate.ddl-auto: create

문제는 ${...} 가 Spring 에서도 사용되는 표현 방식이지만 bash 에서도 그러하다는 점입니다.

- name: Save context to destination
  shell: bash
  run: |
    echo "${{ inputs.context }}" > "${{ inputs.file_dir }}/${{ inputs.file_name }}"

즉, bash 가 위 echo "${{ inputs.context }} ..." 를 실행할 때, 아래처럼 실행되며 에러가 발생했던 것 입니다.

> echo "# prod server has not been set yet

db:
  host:
  username:
  password:
  name:
  port:
  url: jdbc:mysql://${db.host}:${db.port}/${db.name} # <--- 이 부분을 이상하게 인식해버려 error

spring.jpa.hibernate.ddl-auto: create"
> : bad substitution

✅ 문제 해결

결국 근본적인 원인은 bash 가 ${...} 을 평이한 문자열이 아닌 무언가로 인식했기 때문이었습니다.

따라서 해결방법은 "주어진 내용을 문자 그대로" 저장토록 변경하면 됩니다.

- name: Save context to destination
  shell: bash
  run: |
    cat <<'EOF' > "${{ inputs.file_dir }}/${{ inputs.file_name }}"
    ${{ inputs.context }}
    EOF

이를 위해 cat, EOF 를 이용하였고 아래처럼 workflow 가 성공하는 것을 확인하였습니다.


→ 결론

Workflow 스크립트를 작성할 땐 echo 보다 cat 을 애용하자.

profile
나 같은게... 취준?!

0개의 댓글