仅在第一个匹配模式之前插入行块

仅在第一个匹配模式之前插入行块

server {我需要在 /etc/nginx/nginx.conf 中第一个匹配的字符串之前插入以下行(变量替换后)

多变的:

website=www.hello.com

线路块:

server {
# Permanent redirect to www
server_name  ${website:4};
rewrite ^/(.*)$ http://$website/$1 permanent;
}

变量替换后,要插入的行块应如下所示:

server {
# Permanent redirect to www
server_name  hello.com;
rewrite ^/(.*)$ http://www.hello.com/$1 permanent;
}

我所做的以下尝试有两个问题。

问题 1:代码在每个(多个)匹配模式之前添加行块,而不仅仅是第一个。

问题2:变量的值website没有被替换www.hello.com

cat myattempt.sh
awk '
/server {/ {
    print "server {"
    print "# Permanent redirect to www"
    print "server_name  ${website:4};"
    print "rewrite ^/(.*)$ http://$website/$1 permanent;"
    print "}"
}
{ print }
' /etc/nginx/nginx.conf > /etc/nginx/nginx.conf.tmp
mv /etc/nginx/nginx.conf.tmp /etc/nginx/nginx.conf

为了测试我的尝试,创建/etc/nginx/nginx.conf如下

猫 /etc/nginx/nginx.conf

http 
{
#  server   {
}

server  { 
}
}

运行 myattempt.sh

当前输出:cat /etc/nginx/nginx.conf

http 
{

server {
# Permanent redirect to www
server_name  ${website:4};
rewrite ^/(.*)$ http://$website/$1 permanent;
}

#  server   {
}

server {
# Permanent redirect to www
server_name  ${website:4};
rewrite ^/(.*)$ http://$website/$1 permanent;
}
server  { 
}
}

预期输出:

猫 /etc/nginx/nginx.conf

http 
{

server {
# Permanent redirect to www
server_name  hello.com;
rewrite ^/(.*)$ http://www.hello.com/$1 permanent;
}

#  server   {
}

server  { 
}
}

你能建议一下吗?

答案1

这可能就是您想要做的:

$ cat tst.sh
#!/usr/bin/env bash

website=www.hello.com

new='
server {
# Permanent redirect to www
server_name  '"${website:4}"';
rewrite ^/(.*)$ http://'"$website"'/$1 permanent;
}
'

awk -v new="$new" '
    /server *\{/ && !f++ {
        print new
    }
    { print }
' "${@:-}"

$ ./tst.sh file
http
{

server {
# Permanent redirect to www
server_name  hello.com;
rewrite ^/(.*)$ http://www.hello.com/$1 permanent;
}

#  server   {
}

server  {
}
}

使用同名的 shell 变量-v填充 awk 变量将解释转义序列,因此字符串类似于和 ,将变成文本制表符和换行符。如果这是一个问题,请使用或来获取 shell 变量的值,请参阅new\t\nENVIRON[]ARGV[]如何在 awk 脚本中使用 shell 变量

答案2

我不知道是否可以链接sed 答案提出 awk 问题被认为是粗鲁的,但仍然:D

此外,www.由于以下原因,该部分未打印BASH参数扩展。您告诉它从索引 4 开始打印,因此前 4 个字符将被删除。

例子:

$ foo='0123456789'; echo ${foo:3:5}

输出34567

编辑:好吧,这是一个独立的 eval、envsubst、awk 解决方案。

事实证明,多行查找替换是一个 PITA。对于单行搜索多行替换,最好的选择是使用一种语言。我遇到过 awk 的例子用变量查找替换第一次出现替换早于perl -pe解决方案。

# Outputs a space delimetered, dollar-sign prepended text of variables
# e.g. args: 'foo' 'bar'
# output: '$foo $bar'
generate_multi_variable_string() {
    for item in $@; do
        # Prepend dollar-sign to the beginning of all variables, with an escape beforehand
        printf '$'
        printf "$item"
        printf ' '
    done
}

substitute_into_template() {
    template="$1"

    # Rest of the arguments as dollar-sign prepended and space delimetered
    variables="$(generate_multi_variable_string ${@:2})"

    # Export variables for envsubst command to properly function
    for item in ${@:2}; do
        eval "export local $item=\"\$$item\""
    done

    # Here-doc of template, into content of which provided variables are substituted
    envsubst "$variables" << EOF
$template
EOF
}

template='server {
# Permanent redirect to www
server_name  $website;
rewrite ^/(.*)$ http://$website/$1 permanent;'

website='www.hello.com'

match="server {"
replace="$(substitute_into_template "$template" website)"

cat nginx.conf | awk -v srch="$match" -v repl="$replace" '!x{x=sub(srch,repl,$0)} { print $0 }' > new-nginx.conf

相关内容