텍스트 파일에 동일한 이름의 환경 변수가 있는 자리 표시자를 확장하시겠습니까?

텍스트 파일에 동일한 이름의 환경 변수가 있는 자리 표시자를 확장하시겠습니까?

이 질문에는 다양한 변형이 있지만 어쨌든 이 문제에 대한 해결책을 찾는 데 매우 가까워졌기 때문에(!) 여기에 질문하고 싶었습니다. 약간의 노력만 필요합니다.

상상하다

Heroku에서 호스팅되는 Postgres 데이터베이스에 대한 보고서를 실행하는 데 사용하는 여러 텍스트 SQL 파일이 있습니다. 현재 SQL 파일 중 하나는 다음과 같습니다.

SELECT
  (SELECT COUNT(*) FROM metrics WHERE(organization_id = o.id AND year = ${sql_year})) AS metrics,
  (SELECT COUNT(*) FROM my_metrics WHERE(organization_id = o.id)) AS quarterly_metrics,
  (SELECT COUNT(*) FROM quarterly_metrics WHERE(organization_id = o.id AND year = ${sql_year})) AS quarterly_metrics,
  (SELECT COUNT(*) FROM quarterly_text_metrics WHERE(organization_id = o.id AND year = ${sql_year})) AS quarterly_text_metrics,
  (SELECT COUNT(*) FROM budgets WHERE(organization_id = o.id AND year = ${sql_year})) AS budgets,
  (SELECT COUNT(*) FROM goals WHERE(goalable_type = 'Organization' AND goalable_id = o.id AND year = ${sql_year})) AS goals
FROM
  organizations AS o
WHERE
  o.id = ${sql_org_id}
;

저 할 수 있어요좋다다음과 같은 프로세스를 사용하십시오.

export sql_org_id=1; export sql_year=2013
cat reports/my_report.sql | sed -e "s/\(\${[a-zA-Z_]*}\)/`eval "echo '\1'"`/" | heroku pg:psql

이렇게 하면 SQL을 Heroku로 파이프하여 보고서를 생성하고 모든 변수를 스크립트를 실행하기 전에 내보낸 해당 ENV 변수로 바꿀 수 있습니다. 따라서 SQL 파일을 편집하는 대신 즉석에서 변수를 변경하고 다른 보고서를 실행할 수 있습니다.

내 질문

그래서 질문은 내가거의거기에 있지만 나는 그것을 잘 이해하지 못합니다. 내 표현은 다음과 같이 사용할 때 작동합니다 sed.echo

export sql_year=2013
echo "SELECT ${sql_year} AS year" | sed -e "s/\(\${[a-zA-Z_]*}\)/`eval "echo '\1'"`/"

cat하지만 전체 파일 내용을 처리할 수는 없습니다 .

export sql_org_id=1; export sql_year=2013
cat reports/my_report.sql | sed -e "s/\(\${[a-zA-Z_]*}\)/`eval "echo '\1'"`/"

sed와 함께 사용할 때 뭔가 빠졌나요 cat? 도와주세요!

고쳐 쓰다:저는 맥 OS X 10.8을 사용하고 있습니다.

답변1

그리고 zsh:

print -r -- "${(e)$(<reports/my_report.sql)}"

Bourne과 유사한 쉘의 경우(포함 zsh):

eval "cat << EOF
$(cat reports/my_report.sql)
EOF"

`...`둘 다 모두 , $(...), 및 을 $((...))확장 합니다 . 따라서 확장하지 않으려는 달러 문자와 백틱 문자를 이스케이프해야 합니다.$[...]$xxx${xxx}

또한 두 번째 파일의 내용에는 세 문자로 구성된 줄이 포함되어서는 안 됩니다 EOF( SQL문제가 되지 않습니다).

또는 다음을 수행할 수 있습니다.

perl -pe 's/\${(\w+)}/$ENV{$1}/g' reports/my_report.sql

export이를 이해 하려면 이러한 변수가 필요합니다 perl.

솔루션이 작동하지 않고 전혀 작동하지 않는 이유에 대해서는 나중에 실행하여 set -x무슨 일이 일어나고 있는지 확인할 수 있습니다.

$ echo "SELECT ${sql_year} AS year" | sed -e "s/\(\${[a-zA-Z_]*}\)/`eval "echo '\1'"`/"
+ echo 'SELECT 2013 AS year'
++ eval 'echo '\''\1'\'''
+++ echo '\1'
+ sed -e 's/\(${[a-zA-Z_]*}\)/\1/'
SELECT 2013 AS year

큰따옴표를 사용하면 쉘은 echo및 를 호출하기 전에 변수와 명령 대체를 확장합니다 sed. 따라서 실제로 다음을 실행했습니다.

echo 'SELECT 2013 AS year' | sed -e 's/\(${[a-zA-Z_]*}\)/\1/'

sed코드를 실행할 수 없습니다. 따라서 작은따옴표를 사용해도 sed확장되지 않습니다 `...`.

답변2

동일한 작업을 수행하기 위해(또는 일부 템플릿 시스템을 활용하기 위해) 정규 표현식을 작성하는 대신 Bash가 값을 삽입하도록 하겠습니다.

echo $(eval echo $(cat sql.sql))

여기서 sql.sql에는 유효한 bash 문자열이 포함되어 있으므로 큰따옴표로 묶어야 합니다.

"SELECT
  (SELECT COUNT(*) FROM metrics WHERE(organization_id = o.id AND year = ${sql_year})) AS metrics,
  (SELECT COUNT(*) FROM my_metrics WHERE(organization_id = o.id)) AS quarterly_metrics,
  (SELECT COUNT(*) FROM quarterly_metrics WHERE(organization_id = o.id AND year = ${sql_year})) AS quarterly_metrics,
  (SELECT COUNT(*) FROM quarterly_text_metrics WHERE(organization_id = o.id AND year = ${sql_year})) AS quarterly_text_metrics,
  (SELECT COUNT(*) FROM budgets WHERE(organization_id = o.id AND year = ${sql_year})) AS budgets,
  (SELECT COUNT(*) FROM goals WHERE(goalable_type = 'Organization' AND goalable_id =     o.id AND year = ${sql_year})) AS goals
FROM
  organizations AS o
WHERE
  o.id = ${sql_org_id}
;"

답변3

접근 방식을 변경하는 경우 대신 다음을 수행하십시오.

$ heroku pg:psql --app app_name < file.sql

관련 정보