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