使用 Bash/Sed/Awk 在模板文件中查找变量名称?

jwh*_*jwh 2 bash sed

我有一些模板文件,目前正在使用 envsubst 进行处理,效果很好。

<?php

$config['db_host'] = '${DB_HOST}';
$config['db_port'] = '${DB_PORT}';
$config['url'] = 'http://${WEB_HOST}/${WEB_PATH}';

// Please do NOT change this value
$config['maxSize'] = 25;
Run Code Online (Sandbox Code Playgroud)

我试图找到一种使用 bash 脚本扫描文件并生成需要设置的所有环境变量的列表的方法,这样我就可以将它们转储到 .env 文件中,如下所示:

DB_HOST=
DB_PORT=
WEB_HOST=
WEB_PATH=
Run Code Online (Sandbox Code Playgroud)

我认为 sed 是可能的,但是我在 30 分钟的谷歌搜索后找到的所有示例都是关于如何替换内联变量,而不是关于打印出匹配项。

小智 5

您的标准似乎是:匹配${和之间包含的任意数量的大写字母或下划线}之间包含的任意数量的大写字母或下划线。

\n\n

gawk可以自己解决这个问题,或者grep可以简化模式匹配部分(但之后需要额外的格式化)。

\n\n
\n\n

GNUawk

\n\n
gawk -v \'RS=[$]{\' -F \'}\' \'$1 ~ /^[A-Z_]+$/ && !a[$1]++ {printf "%s=\\n", $1}\' FILE\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • GNU awk 可以接受记录分隔符的正则表达式,因此通过分配RS=[$]{,它将把输入分割FILE成记录,无论模式如何${出现的任何地方将输入拆分为记录
  • \n
  • 字段分隔符设置为}\xe2\x80\x93 现在可以检查每个记录的第一个字段以查看它是否符合您的其他条件:除了一个或多个[A-Z_]
  • \n
  • 使用&& !a[$1]++将删除重复项
  • \n
  • print 语句添加一个等号=在每行末尾添加一个等号 \xe2\x80\x93 以匹配您所需的输出
  • \n
  • 另请注意:文件的第一部分将始终被计为第一条记录 \xe2\x80\x93,即使它不以${\xe2\x80\x93 开头,这意味着如果您的文件以[A-Z_]+}(不太可能)\开头xe2\x80\x93 这些大写字母/下划线将“匹配”并打印在输出的第一行
  • \n
\n\n
\n\n

grep+ 格式化

\n\n

grep也许更容易理解(感谢它的-o/--only-matching选项):

\n\n
grep -o \'${[A-Z_]\\+}\' FILE\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • 但这不会格式化输出:通过管道sed可以做到这一点:例如。
  • \n
\n\n
grep -o \'${[A-Z_]\\+}\' FILE | sed \'s/${\\(.*\\)}/\\1=/\'\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  • 这不会删除重复项:通过管道输出sort -u来做到这一点,或者通过 awk 管道一次:
  • \n
\n\n
grep -o \'${[A-Z_]\\+}\' FILE | awk -F \'[{}]\' \'!a[$0]++{printf "%s=\\n", $2}\'\n
Run Code Online (Sandbox Code Playgroud)\n