使用vanilla Ubuntu,一个搜索和替换/取消注释代码块的脚本?

时间:2015-10-12 10:18:52

标签: bash perl ubuntu nginx sed

我正在尝试在开发环境的Ubuntu 14.04中自动安装,部分原因是我需要取消注释Nginx vHost配置的代码块:

    #location ~ \.php$ {
    #       fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #       # With php5-cgi alone:
    #       fastcgi_pass 127.0.0.1:9000;
    #       # With php5-fpm:
    #       fastcgi_pass unix:/var/run/php5-fpm.sock;
    #       fastcgi_index index.php;
    #       include fastcgi_params;
    #}

我试过sed:

sed -i "s/#location ~ \.php$ {
        #       fastcgi_split_path_info ^(.+\.php)(/.+)$;
        #       # NOTE: You should have \"cgi.fix_pathinfo = 0;\" in php.ini
        #
        #       # With php5-cgi alone:
        #       fastcgi_pass 127.0.0.1:9000;
        #       # With php5-fpm:
        #       fastcgi_pass unix:/var/run/php5-fpm.sock;
        #       fastcgi_index index.php;
        #       include fastcgi_params;
        #}/location ~ \.php$ {
          fastcgi_split_path_info ^(.+\.php)(\/.+)$;
          # NOTE: You should have \"cgi.fix_pathinfo = 0;\" in php.ini

          # With php5-cgi alone:
          fastcgi_pass 127.0.0.1:9000;
          # With php5-fpm:
          fastcgi_pass unix:\/var\/run\/php5-fpm.sock;
          fastcgi_index index.php;
          include fastcgi_params;
        }/g" /etc/nginx/sites-available/nginx.dev;

但是这会回来:

sed: -e expression #1, char 22: unterminated `s' command

我假设与语法错误有关,我试图逃避/"字符,但我认为这还不够/正确。

我发现了这个:https://unix.stackexchange.com/a/26289/138115

这表明perl可能是一个很好的解决方案,因为它与Ubuntu一起安装我试过了:

perl -0777 -i.original -pe 's/#location ~ \.php$ {\n        #       fastcgi_split_path_info ^(.+\.php)(\/.+)$;\n        #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini\n        #\n        #       # With php5-cgi alone:\n        #       fastcgi_pass 127.0.0.1:9000;\n        #       # With php5-fpm:\n        #       fastcgi_pass unix:\/var\/run\/php5-fpm.sock;\n        #       fastcgi_index index.php;\n        #       include fastcgi_params;\n        #}/slocation ~ \.php$ {\n  fastcgi_split_path_info ^(.+\.php)(\/.+)$;\n  NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini\n  With php5-cgi alone:\n  fastcgi_pass 127.0.0.1:9000;\n  With php5-fpm:\n  fastcgi_pass unix:\/var\/run\/php5-fpm.sock;\n  fastcgi_index index.php;\n  include fastcgi_params;\n}/igs' /etc/nginx/sites-available/nginx.dev;

但这会产生大量语法错误:

syntax error at -e line 1, near "(."
Unknown regexp modifier "/v" at -e line 1, within string
Unknown regexp modifier "/r" at -e line 1, within string
Unknown regexp modifier "/h" at -e line 1, within string
Unknown regexp modifier "/5" at -e line 1, within string
Not enough arguments for index at -e line 1, near "index."
syntax error at -e line 1, near "n}"
Execution of -e aborted due to compilation errors.

我之前为各种环境写了很多这样的脚本,但我总是试图避免替换多行文本,因为我从来没能做到这一点。今天,我已经花了3个小时,我仍然没有真正了解如何使这项工作。如果有人可以分享一些输入/洞察力以及如何实现它,那么非常感谢,谢谢!

修改1:

使用方括号简单转义:

#!/bin/bash
#/etc/nginx/sites-available/test.sh
file=$(<default.file);
search=$(<nginx_search.txt);
replace=$(<nginx_replace.txt);
$file =~ s[$search][$replace]g;
echo "$file" > "/etc/nginx/sites-available/test.file";
# Outputs notice: ./test.sh: line 6: #: command not found

test.file已创建,但它包含原始值default.file,但没有修改。

在perl中测试后,我收到:

syntax error at ./perl.perl line 6, near "(."
Unknown regexp modifier "/v" at ./perl.perl line 6, within string
Unknown regexp modifier "/r" at ./perl.perl line 6, within string
Unknown regexp modifier "/h" at ./perl.perl line 6, within string
Unknown regexp modifier "/5" at ./perl.perl line 6, within string
syntax error at ./perl.perl line 9, near ";
}"
Execution of ./perl.perl aborted due to compilation errors.

第6行写道:

#       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

2 个答案:

答案 0 :(得分:1)

注意 - 你提到(并标记)perl。以下是perl的观点。其中一些可能适用于传统的外壳,但我无法确切地说出什么。 perl确实支持超出基本POSIX规范的一些正则表达式。

这种模式的问题在于,你的模式中有分隔符。你的初始失败是因为它会处理这个斜杠:

    #       fastcgi_pass unix:/var/run/php5-fpm.sock;

作为&#39;分裂点&#39;在模式中。你可以通过转义分隔符来解决这个问题,但实际上更好的办法是 - 使用其他地方不存在的分隔符。在上文中,我建议您使用方括号:

my $str = "some fish"; 
$str =~ s[some][more]g;

print $str;

虽然作为替代方案 - 您可以使用range operator测试为&#39; true&#39;如果它在两个指定的分隔符内:

while ( <> ) {
   if ( m|\#location.*php\$ \{| .. m|^\s*#\}| ) {
       s/#//;
   }
   print ;
}

E.g:

#!/usr/bin/perl
use strict;
use warnings;


while ( <DATA> ) {
   if ( m|\#location.*php\$ \{| .. m|^\s*#\}| ) {
       #note - no g modifier, so we only do the first per line
       s/#//;
   }
   print ;
}

__DATA__
# Some stuff
we don't care about this line
#and this shouldn't be changed

#but after this point, it should be!

   #location ~ \.php$ {
    #       fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #       # With php5-cgi alone:
    #       fastcgi_pass 127.0.0.1:9000;
    #       # With php5-fpm:
    #       fastcgi_pass unix:/var/run/php5-fpm.sock;
    #       fastcgi_index index.php;
    #       include fastcgi_params;
    #}


# and now we stop, and leave this bit alone. 

    more stuff; 
    here; 
    # and another comment line

如果你在两个分隔符之间(位置php和&#39;关闭波浪形括号&#39;在上面),这有条件地应用变换。

你可以单行 - 如果这样:

perl -ne 'if ( m|\#location.*php\$ \{| .. m|^\s*#\}| ) { s/#//g; } print' myfile

(如果要进行编辑,请添加-i)。

答案 1 :(得分:1)

我认为,这些长字符串替换总是挑剔的,并且通常最好尽量避免处理内容。我想出了这个,它只是捕获字符串,带走第一个#并重新打印该行:

use strict;
use warnings;

my $search = q|#location ~ \.php$ {
    #       fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #       # With php5-cgi alone:
    #       fastcgi_pass 127.0.0.1:9000;
    #       # With php5-fpm:
    #       fastcgi_pass unix:/var/run/php5-fpm.sock;
    #       fastcgi_index index.php;
    #       include fastcgi_params;
    #}
|;

local $/;   # slurp the file
while (<DATA>) {
    s|(\Q$search\E)| my $x = $1; $x =~ s/^\s*#//mg; $x; |e;
    print;
}    
__DATA__
    # stuff
    #location ~ \.php$ {
    #       fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #       # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #       # With php5-cgi alone:
    #       fastcgi_pass 127.0.0.1:9000;
    #       # With php5-fpm:
    #       fastcgi_pass unix:/var/run/php5-fpm.sock;
    #       fastcgi_index index.php;
    #       include fastcgi_params;
    #}
    #comment

注意使用\Q ... \E来避免字符串中的正则表达式元字符让你感到困惑。

使用此方法,您应该能够从文件中读取搜索字符串(如果您需要)。