如何使用 shell 脚本更改文件中标签之间的特定内容?

How do I change specific content between tags in a file using shell script?

我有一个虚拟主机 apache 配置文件,我想使用 shell 脚本更改标记 <VirtualHost *:80></VirtualHost> 内的所有内容。

我在 virtualhost.conf 中有这个:

<VirtualHost *:80>
    ServerName mysite.foo.bar

    DocumentRoot /var/www/html/src/

    <Directory /var/www/html/src/>
        Require all granted
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ index.php?m= [QSA]
        DirectoryIndex index.php
    </Directory>
</VirtualHost>

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName mysite.foo.bar

        DocumentRoot /var/www/html/src/

        <Directory /var/www/html/src/>
            Require all granted
            RewriteEngine on
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteRule ^(.*)$ index.php?m= [QSA]
            DirectoryIndex index.php
        </Directory>

        SSLCertificateFile /etc/foo/bar/fullchain.pem
        SSLCertificateKeyFile /etc/foo/bar/privkey.pem
        Include /etc/foo/options-ssl-apache.conf
    </VirtualHost>
</IfModule>    

并且,使用 shell 脚本,我想为此更改它:

<VirtualHost *:80>
    ServerName mysite.foo.bar
    Redirect permanent / https://mysite.foo.bar/
</VirtualHost>

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName mysite.foo.bar

        DocumentRoot /var/www/html/src/

        <Directory /var/www/html/src/>
            Require all granted
            RewriteEngine on
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteCond %{REQUEST_FILENAME} !-d
            RewriteRule ^(.*)$ index.php?m= [QSA]
            DirectoryIndex index.php
        </Directory>
        
        SSLCertificateFile /etc/foo/bar/fullchain.pem
        SSLCertificateKeyFile /etc/foo/bar/privkey.pem
        Include /etc/foo/options-ssl-apache.conf
    </VirtualHost>
</IfModule>

换句话说,我想将端口 80 上的所有流量重定向到端口 443,但我需要在我的进程中自动执行此更改。

使用 awk:

awk 'BEGIN { mark=1 } /^<VirtualHost \*:80>/ { print;printf "\tServerName mysite.foo.bar\n\tRedirect permanent / https://mysite.foo.bar/\n";mark=0;next } /<\/VirtualHost>/ { mark=1 }mark' file

解释:

awk 'BEGIN { 
                mark=1                                                        # Set a print marker (mark) to 1 before file processing
           } 
     /^<VirtualHost \*:80>/ {                                                  # Process when we see a Virtual Host on 80
                print;                                                         # Print the line
                printf "\tServerName mysite.foo.bar\n\tRedirect permanent / https://mysite.foo.bar/\n";                                                          # Print the additional text
                mark=0;                                                        # Set print marker to 0
                next                                                           # Skip to the next line
            } 
      /<\/VirtualHost>/ {                                                      # Process when we see a closing Virtual Host tag
                mark=1                                                         # Set print marker to 1
            }mark' file                                                        # Use print marker to distinguish what should and shouldn't print

使用 GNU sed:

sed -E '
/^\s*<VirtualHost\s.*:80>\s*$/,/^\s*<\/VirtualHost>\s*$/{
    /^\s*<\/?VirtualHost.*>\s*$/b
    /^\s*ServerName\s+(\S+).*/!d
    s%%&\n    Redirect permanent / https:///%
}' virtualhost.conf